├── .flake8 ├── .github ├── dependabot.yml └── workflows │ ├── bin │ └── collect_tests.py │ ├── ci.yml │ ├── lint.yml │ └── wheels.yml ├── .gitignore ├── .gitmodules ├── AUTHORS ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── docs ├── _images │ ├── bad_valid_toggle.svg │ ├── example_rw_xaction.svg │ ├── hokusai.jpg │ ├── hokusai_full.jpg │ ├── ok_double_xaction.svg │ ├── ok_ready_toggle.svg │ ├── ok_ready_valid.svg │ ├── ok_sametime.svg │ ├── ok_valid_ready.svg │ ├── ready_valid.svg │ ├── sumi_connections.png │ ├── sumi_connections.svg │ ├── swizzle_lumi.png │ ├── tumi_connections.png │ ├── tumi_connections.svg │ ├── umi_connections.png │ └── umi_stack.svg └── umi_waveforms.py ├── examples └── regfile │ ├── README.md │ ├── test.py │ └── testbench.sv ├── pyproject.toml ├── tests ├── conftest.py └── test_lint.py └── umi ├── __init__.py ├── conftest.py ├── lumi ├── README.md ├── __init__.py ├── rtl │ ├── lumi.v │ ├── lumi_crossbar.v │ ├── lumi_regmap.vh │ ├── lumi_regs.v │ ├── lumi_rx.v │ ├── lumi_rx_ready.v │ ├── lumi_tx.v │ └── lumi_tx_ready.v ├── testbench │ ├── config.vlt │ ├── testbench_lumi.sv │ └── testbench_lumi_ready.sv └── tests │ ├── conftest.py │ ├── test_lumi.py │ ├── test_lumi_ready.py │ └── test_lumi_rnd.py ├── sumi ├── __init__.py ├── rtl │ ├── umi_arbiter.v │ ├── umi_crossbar.v │ ├── umi_decode.v │ ├── umi_demux.v │ ├── umi_endpoint.v │ ├── umi_fifo.v │ ├── umi_fifo_flex.v │ ├── umi_isolate.v │ ├── umi_mem_agent.v │ ├── umi_messages.vh │ ├── umi_mux.v │ ├── umi_mux_old.v │ ├── umi_pack.v │ ├── umi_pipeline.v │ ├── umi_priority.v │ ├── umi_ram.v │ ├── umi_regif.v │ ├── umi_splitter.v │ ├── umi_switch.v │ ├── umi_tester.v │ └── umi_unpack.v ├── testbench │ ├── config.vlt │ ├── cpp │ │ └── umi_testbench.cc │ ├── dut_umi_fifo.v │ ├── dut_umi_fifo_flex.v │ ├── testbench_crossbar.sv │ ├── testbench_demux.sv │ ├── testbench_fifo.sv │ ├── testbench_fifo_flex.sv │ ├── testbench_isolate.sv │ ├── testbench_mem_agent.sv │ ├── testbench_mux.sv │ ├── testbench_regif.sv │ ├── testbench_switch.sv │ ├── testbench_umi_ram.sv │ └── umi_testbench.py └── tests │ ├── conftest.py │ ├── test_crossbar.py │ ├── test_demux.py │ ├── test_fifo.py │ ├── test_fifo_flex.py │ ├── test_isolate.py │ ├── test_mem_agent.py │ ├── test_mux.py │ ├── test_regif.py │ ├── test_switch.py │ └── test_umi_ram.py └── utils ├── rtl ├── README.md ├── axilite2umi.v ├── tl-uh.vh ├── tl2umi_np.v ├── umi2apb.v ├── umi2axilite.v ├── umi2tl_np.v ├── umi_address_remap.v ├── umi_data_aggregator.v └── umi_packet_merge_greedy.v └── testbench ├── buffer.memh ├── buffer_axilite.memh ├── config.h ├── config.vlt ├── tb_axilite2umi.v ├── tb_tl2umi_np.v ├── tb_umi_data_aggregator.v ├── test_tl2umi_np.py ├── test_umi2apb.py ├── test_umi2axilite.py ├── test_umi2tl_np.py ├── test_umi_address_remap.py ├── test_umi_packet_merge_greedy.py ├── testbench_umi2apb.sv ├── testbench_umi2axilite.sv ├── testbench_umi2tl_np.cc ├── testbench_umi2tl_np.v ├── testbench_umi_address_remap.v ├── testbench_umi_packet_merge_greedy.cc ├── testbench_umi_packet_merge_greedy.v ├── tilelink.h ├── tlmemsim.cpp └── tlmemsim.h /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 120 3 | extend-ignore = 4 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Maintain dependencies for GitHub Actions 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "weekly" 8 | groups: 9 | actions: 10 | patterns: 11 | - "*" 12 | # Maintain dependencies for Python 13 | - package-ecosystem: pip 14 | directory: "/" 15 | schedule: 16 | interval: "weekly" 17 | groups: 18 | python-packages: 19 | patterns: 20 | - "*" 21 | -------------------------------------------------------------------------------- /.github/workflows/bin/collect_tests.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | 4 | 5 | if __name__ == "__main__": 6 | script_dir = os.path.dirname(os.path.abspath(__file__)) 7 | repo_dir = os.path.abspath(os.path.join(script_dir, '..', '..', '..')) 8 | tests = [] 9 | for dirpath, dirnames, filenames in os.walk(repo_dir): 10 | for f in filenames: 11 | if f.startswith("test_"): 12 | tests.append(os.path.join(dirpath, f)) 13 | 14 | tests_rel = [os.path.relpath(p, repo_dir) for p in tests] 15 | 16 | print(json.dumps({"testbench": tests_rel})) 17 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Testbench CI 2 | on: 3 | # Runs on all PRs 4 | pull_request: 5 | # Manual Dispatch 6 | workflow_dispatch: 7 | 8 | jobs: 9 | switchboard_ci: 10 | name: "Switchboard CI" 11 | runs-on: ubuntu-latest 12 | container: 13 | image: ghcr.io/zeroasiccorp/sbtest:latest 14 | timeout-minutes: 10 15 | 16 | steps: 17 | - name: Checkout repository 18 | uses: actions/checkout@v4 19 | 20 | - name: pytest 21 | run: | 22 | python3 -m venv venv 23 | . venv/bin/activate 24 | python3 -m pip install --upgrade pip 25 | python3 -m pip install -e .[test] 26 | pytest -m "switchboard" 27 | 28 | python_ci: 29 | name: "Python + Tools CI" 30 | runs-on: ubuntu-latest 31 | container: 32 | image: ghcr.io/siliconcompiler/sc_tools:latest 33 | timeout-minutes: 10 34 | 35 | steps: 36 | - name: Checkout repository 37 | uses: actions/checkout@v4 38 | 39 | - name: pytest 40 | run: | 41 | python3 -m venv venv 42 | . venv/bin/activate 43 | python3 -m pip install --upgrade pip 44 | python3 -m pip install -e .[test] 45 | pytest -m "not switchboard" -n auto 46 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint UMI 2 | on: 3 | pull_request: 4 | workflow_dispatch: 5 | push: 6 | branches: main 7 | 8 | jobs: 9 | lint_python: 10 | name: Lint Python Code 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Check out Git repository 14 | uses: actions/checkout@v4 15 | - name: Lint with Flake8 16 | run: | 17 | pip install --upgrade pip 18 | pip install .[test] 19 | flake8 --statistics . 20 | -------------------------------------------------------------------------------- /.github/workflows/wheels.yml: -------------------------------------------------------------------------------- 1 | name: Wheels 2 | 3 | on: 4 | workflow_dispatch: 5 | release: 6 | types: 7 | - published 8 | 9 | jobs: 10 | build_wheels: 11 | name: Wheels UMI 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | with: 17 | submodules: true 18 | - uses: hynek/build-and-inspect-python-package@v2 19 | 20 | publish: 21 | needs: [build_wheels] 22 | runs-on: ubuntu-latest 23 | permissions: 24 | id-token: write 25 | if: github.event_name == 'release' && github.event.action == 'published' 26 | 27 | steps: 28 | - uses: actions/download-artifact@v4 29 | with: 30 | name: Packages 31 | path: dist 32 | 33 | - name: Publish 34 | uses: pypa/gh-action-pypi-publish@v1.12.4 35 | 36 | save: 37 | needs: [publish] 38 | runs-on: ubuntu-latest 39 | 40 | permissions: 41 | contents: write 42 | 43 | steps: 44 | - uses: actions/download-artifact@v4 45 | with: 46 | name: Packages 47 | path: dist 48 | 49 | - name: Add wheels to GitHub release artifacts 50 | uses: softprops/action-gh-release@v2 51 | with: 52 | files: dist/*.whl 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ###################### 2 | # Compiled binaries 3 | *.elf 4 | *.o 5 | *.e 6 | *.d 7 | 8 | ###################### 9 | # test results 10 | *.q 11 | *.vcd 12 | *.fst 13 | build/ 14 | gmon.out 15 | coverage.dat 16 | 17 | ###################### 18 | # Emacs/vim/gedit backup files 19 | *~ 20 | .*.swp 21 | .*.swo 22 | *# 23 | *.bak 24 | 25 | ###################### 26 | # Python 27 | __pycache__/ 28 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeroasiccorp/umi/f43b42fab7a49748a7eb0e01383478141ff79d5f/.gitmodules -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Andreas Olofsson 2 | Amir Volk 3 | Steven Herbst 4 | Edgar Iglesias 5 | Aliasger Zaidy 6 | Wenting Zhang 7 | Peter Grossmann 8 | Noah Moroze 9 | Ben Sheffer 10 | -------------------------------------------------------------------------------- /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, caste, color, religion, or sexual 11 | identity 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 overall 27 | community 28 | 29 | Examples of unacceptable behavior include: 30 | 31 | * The use of sexualized language or imagery, and sexual attention or advances of 32 | 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 address, 36 | 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 report@zeroasic.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series of 86 | actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or permanent 93 | ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within the 113 | community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.1, available at 119 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. 120 | 121 | Community Impact Guidelines were inspired by 122 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. 123 | 124 | For answers to common questions about this code of conduct, see the FAQ at 125 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at 126 | [https://www.contributor-covenant.org/translations][translations]. 127 | 128 | [homepage]: https://www.contributor-covenant.org 129 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html 130 | [Mozilla CoC]: https://github.com/mozilla/diversity 131 | [FAQ]: https://www.contributor-covenant.org/faq 132 | [translations]: https://www.contributor-covenant.org/translations 133 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | How to contribute to Universal Memory Interface (UMI) 2 | ===================================================== 3 | 4 | Thank you for considering contributing to the UMI project! 5 | 6 | ## General guidelines 7 | - Start small, relationships need time to grow 8 | - All new features must come with tests 9 | - Keep PRs short to simplify review 10 | - Large PRs should be preceded by discussions 11 | - Discuss with core team before proposing core changes 12 | - PRs should include changes only to files related to change 13 | - Comply with coding guidelines/style of project 14 | - Avoid style only code based PRs 15 | 16 | #### Reporting issues 17 | 18 | Include the following information in your post: 19 | 20 | - Describe what you expected to happen 21 | - Include a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) 22 | - Describe what actually happened 23 | - Include the full traceback if there was an exception 24 | - List your Python and UMI versions 25 | - Check if this issue is already fixed in the latest releases 26 | 27 | ## Submitting patches 28 | 29 | If there is not an open issue for what you want to submit, prefer opening one 30 | for discussion before working on a PR. You can work on any issue that doesn't 31 | have an open PR linked to it or a maintainer assigned to it. These show up in 32 | the sidebar. No need to ask if you can work on an issue that interests you. 33 | 34 | Include the following in your patch: 35 | 36 | - Include tests if your patch adds or changes code.(should fail w/o patch) 37 | - Update any relevant docs pages and docstrings 38 | 39 | 40 | ## First time setup 41 | 42 | - Download and install [git](https://git-scm.com/downloads) 43 | 44 | - Configure your [git username](https://docs.github.com/en/github/using-git/setting-your-username-in-git) 45 | 46 | - Configure your [git email](https://docs.github.com/en/github/setting-up-and-managing-your-github-user-account/setting-your-commit-email-address) 47 | 48 | ```sh 49 | $ git config --global user.name 'your name' 50 | $ git config --global user.email 'your email' 51 | ``` 52 | - Make sure you have a [github account](https://github.com/join) 53 | 54 | 55 | ## Clone/Fork Repository 56 | 57 | - [Fork UMI]( https://github.com/zeroasiccorp/umi/fork) to your GitHub account (external contributors only) 58 | 59 | - [Clone](https://docs.github.com/en/github/getting-started-with-github/fork-a-repo#step-2-create-a-local-clone-of-your-fork) the main repository locally. 60 | 61 | ```sh 62 | $ git clone https://github.com/{username}/umi 63 | $ cd umi 64 | ``` 65 | 66 | - Add fork as a remote to push your work to. (external contributors only) 67 | 68 | ```sh 69 | $ git remote add fork https://github.com/{username}/umi 70 | ``` 71 | 72 | ## Start coding 73 | 74 | - Create a branch to identify the issue you would like to work on. 75 | 76 | ```sh 77 | $ git fetch origin 78 | $ git checkout -b your-branch-name origin/main 79 | ``` 80 | - Using your favorite editor, make your changes, and [commit](https://dont-be-afraid-to-commit.readthedocs.io/en/latest/git/commandlinegit.html#commit-your-changes) 81 | 82 | - Include tests that cover any code changes you make. Make sure the test fails without your patch. Run the tests as described below. 83 | 84 | - Push your commits to your fork on GitHub (external contributors) 85 | 86 | ```sh 87 | $ git push --set-upstream fork your-branch-name 88 | ``` 89 | 90 | - Push your commits to your umi branch on GitHub (team contributors) 91 | ```sh 92 | $ git push -u origin your-branch-name 93 | ``` 94 | 95 | 96 | ## Running the tests 97 | 98 | Testbench and run scripts are provided for some of the modules in /testbench 99 | Where applicable the testbench and test suite need to be updated for contributing to this project and committed together with the code changes. 100 | 101 | ## Create a Pull Request 102 | 103 | - Create a [pull request](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request) through github. 104 | 105 | ## Resources ### 106 | 107 | Original version based on [Flask contribution guidelines](https://flask.palletsprjects.com/en/2.0.x/contributing/) 108 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | If you believe you have identified a security issue with a UMI project, do not open a public issue. To responsibly report a security issue, please email security@zeroasic.com. A security team member will contact you acknowledging the report and how to continue. 4 | 5 | Be sure to include as much detail as necessary in your report. If you are able, you may also include a fix for the issue generated with git format-patch. 6 | 7 | After fixing an issue, we will make a security release along with an announcement. We may obtain a CVE id as well. You may include a name and link if you would like to be credited for the report. 8 | -------------------------------------------------------------------------------- /docs/_images/hokusai.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeroasiccorp/umi/f43b42fab7a49748a7eb0e01383478141ff79d5f/docs/_images/hokusai.jpg -------------------------------------------------------------------------------- /docs/_images/hokusai_full.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeroasiccorp/umi/f43b42fab7a49748a7eb0e01383478141ff79d5f/docs/_images/hokusai_full.jpg -------------------------------------------------------------------------------- /docs/_images/sumi_connections.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeroasiccorp/umi/f43b42fab7a49748a7eb0e01383478141ff79d5f/docs/_images/sumi_connections.png -------------------------------------------------------------------------------- /docs/_images/swizzle_lumi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeroasiccorp/umi/f43b42fab7a49748a7eb0e01383478141ff79d5f/docs/_images/swizzle_lumi.png -------------------------------------------------------------------------------- /docs/_images/tumi_connections.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeroasiccorp/umi/f43b42fab7a49748a7eb0e01383478141ff79d5f/docs/_images/tumi_connections.png -------------------------------------------------------------------------------- /docs/_images/umi_connections.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeroasiccorp/umi/f43b42fab7a49748a7eb0e01383478141ff79d5f/docs/_images/umi_connections.png -------------------------------------------------------------------------------- /docs/umi_waveforms.py: -------------------------------------------------------------------------------- 1 | import wavedrom 2 | 3 | ###################### 4 | # READY VALID 5 | ###################### 6 | svg = wavedrom.render(""" 7 | { "signal": [ 8 | { "name": "clk", "wave": "P........", period=2}, 9 | { "name": "valid_out", "wave": "0.1.01..0"}, 10 | { "name": "packet_out", "wave": "x.23x4.5x", "data": "P0 P1 P2 P3"}, 11 | { "name": "ready_in", "wave": "1....01.."}, 12 | 13 | ]}""") 14 | svg.saveas("_images/ready_valid.svg") 15 | 16 | ###################### 17 | # Transaction Examples 18 | ###################### 19 | # Okay: Valid before ready. 20 | svg = wavedrom.render(""" 21 | { 22 | "signal": [ 23 | { "node": ".....-..", phase: 0.2 }, 24 | { "name": "clk", "wave": "P.......", period = 2 }, 25 | { "name": "packet", "wave": "x..2.x..", "data": "Data" }, 26 | { "name": "valid", "wave": "0..1.0.." }, 27 | { "name": "ready", "wave": "0...10..", }, 28 | { "node": "....._..", phase: 0.2 }, 29 | ], 30 | "edge": [ 31 | "-|_ sample" 32 | ], 33 | } 34 | """) 35 | svg.saveas("_images/ok_valid_ready.svg") 36 | 37 | # Okay: Ready before valid. 38 | svg = wavedrom.render(""" 39 | { 40 | "signal": [ 41 | { "node": "......-.", phase: 0.2 }, 42 | { "name": "clk", "wave": "P.......", period = 2 }, 43 | { "name": "packet", "wave": "x....2x.", "data": "Data" }, 44 | { "name": "valid", "wave": "0....10." }, 45 | { "name": "ready", "wave": "01....0." }, 46 | { "node": "......_.", phase: 0.2 }, 47 | ], 48 | "edge": [ 49 | "-|_ sample" 50 | ], 51 | } 52 | """) 53 | svg.saveas("_images/ok_ready_valid.svg") 54 | 55 | # Okay: Ready and valid in same cycle. 56 | svg = wavedrom.render(""" 57 | { 58 | "signal": [ 59 | { "node": "......-.", phase: 0.2 }, 60 | { "name": "clk", "wave": "P.......", period = 2 }, 61 | { "name": "packet", "wave": "x....2x.", "data": "Data" }, 62 | { "name": "valid", "wave": "0....10." }, 63 | { "name": "ready", "wave": "0....10." }, 64 | { "node": "......_.", phase: 0.2 }, 65 | ], 66 | "edge": [ 67 | "-|_ sample" 68 | ], 69 | } 70 | """) 71 | svg.saveas("_images/ok_sametime.svg") 72 | 73 | # Okay: Ready toggles without valid.. 74 | svg = wavedrom.render(""" 75 | { 76 | "signal": [ 77 | { "node": "......-.", phase: 0.2 }, 78 | { "name": "clk", "wave": "P.......", period = 2 }, 79 | { "name": "packet", "wave": "x....2x.", "data": "Data" }, 80 | { "name": "valid", "wave": "0....10." }, 81 | { "name": "ready", "wave": "010..10." }, 82 | { "node": "......_.", phase: 0.2 }, 83 | ], 84 | "edge": [ 85 | "-|_ sample" 86 | ], 87 | } 88 | """) 89 | svg.saveas("_images/ok_ready_toggle.svg") 90 | 91 | # NOT okay: Valid toggles without ready. 92 | svg = wavedrom.render(""" 93 | { 94 | "signal": [ 95 | { "name": "clk", "wave": "P.......", period = 2 }, 96 | { "name": "packet", "wave": "x4x..2x.", "data": "XXX Data" }, 97 | { "name": "valid", "wave": "010..10." }, 98 | { "name": "ready", "wave": "0....10." }, 99 | ], 100 | } 101 | """) 102 | svg.saveas("_images/bad_valid_toggle.svg") 103 | 104 | # Okay: Valid held high for two cycles (two transactions) 105 | svg = wavedrom.render(""" 106 | { 107 | "signal": [ 108 | { "node": ".....-=.", phase: 0.2 }, 109 | { "name": "clk", "wave": "P.......", period = 2 }, 110 | { "name": "packet", "wave": "x...2.x.", "data": "Data" }, 111 | { "name": "valid", "wave": "0...1.0." }, 112 | { "name": "ready", "wave": "0.1...0." }, 113 | { "node": "....._!.", phase: 0.2 }, 114 | ], 115 | "edge": [ 116 | "-|_ sample 1", "=|! sample 2", 117 | ], 118 | } 119 | """) 120 | svg.saveas("_images/ok_double_xaction.svg") 121 | 122 | # Example 'read' transaction: TX to request read, RX to receive. 123 | svg = wavedrom.render(""" 124 | { 125 | "signal": [ 126 | { "node": "...=..-.", phase: 0.2 }, 127 | { "name": "clk", "wave": "P.......", period = 2 }, 128 | { "name": "packet_in", "wave": "x2.x....", "data": "Req" }, 129 | { "name": "valid_in", "wave": "01.0...." }, 130 | { "name": "ready_in", "wave": "0.10...." }, 131 | { "name": "packet_out", "wave": "x....2x.", "data": "Resp" }, 132 | { "name": "valid_out", "wave": "0....10." }, 133 | { "name": "ready_out", "wave": "0..1..0." }, 134 | { "node": "...!.._.", phase: 0.2 }, 135 | ], 136 | "edge": [ 137 | "-|_ sample out", "=|! sample in" 138 | ], 139 | } 140 | """) 141 | svg.saveas("_images/example_rw_xaction.svg") 142 | -------------------------------------------------------------------------------- /examples/regfile/README.md: -------------------------------------------------------------------------------- 1 | # Register File Example 2 | 3 | This example shows how to connect UMI to a simple register file. The `testbench.sv` instantiates `umi_regif` and a an array of registers. Transactions are driven using `switchboard` UMI transactors instantiated within the `testbench.sv`. 4 | 5 | To run the example, execute test.py from the command line: 6 | 7 | ```bash 8 | ./test.py 9 | ``` 10 | 11 | You'll see a Verilator based build, followed by output like this. A simulation waveform is recorded in `testbench.vcd` 12 | 13 | ```text 14 | Read addr=0 data=[0xef 0x0 0x0 0x0] 15 | Read addr=0 data=[0xef 0xbe 0x0 0x0] 16 | Read addr=0 data=[0xef 0xbe 0xad 0xde] 17 | Read addr=200 data=[0xa0 0xa0 0xa0 0xa0] 18 | Read addr=0 data=[0xef 0xbe 0xad 0xde] 19 | ``` 20 | -------------------------------------------------------------------------------- /examples/regfile/test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2025 Zero ASIC 4 | # This code is licensed under Apache License 2.0 (see LICENSE for details) 5 | 6 | import numpy as np 7 | from switchboard import SbDut, UmiTxRx 8 | from umi import sumi 9 | 10 | 11 | def main(): 12 | # build the simulator 13 | dut = build_testbench() 14 | 15 | # launch the simulation 16 | dut.simulate( 17 | plusargs=[ 18 | ('valid_mode', dut.args.vldmode), 19 | ('ready_mode', dut.args.rdymode) 20 | ] 21 | ) 22 | 23 | # Switchboard queue initialization 24 | umi = UmiTxRx('host2dut_0.q', 'dut2host_0.q', fresh=True) 25 | 26 | np.set_printoptions(formatter={'int': hex}) 27 | 28 | print("### Starting test ###") 29 | # regif accesses are all 32b wide and aligned 30 | 31 | umi.write(0, np.uint8(0xef)) 32 | read_data = umi.read(0, 4) 33 | print(f'Read addr=0 data={read_data}') 34 | 35 | umi.write(0, np.uint16(0xbeef)) 36 | read_data = umi.read(0, 4) 37 | print(f'Read addr=0 data={read_data}') 38 | 39 | umi.write(0, np.uint32(0xdeadbeef)) 40 | read_data = umi.read(0, 4) 41 | print(f'Read addr=0 data={read_data}') 42 | 43 | umi.write(200, np.uint32(0xa0a0a0a0)) 44 | read_data = umi.read(200, 4) 45 | print(f'Read addr=200 data={read_data}') 46 | 47 | read_data = umi.read(0, 4) 48 | print(f'Read addr=0 data={read_data}') 49 | 50 | 51 | def build_testbench(fast=False): 52 | 53 | extra_args = { 54 | '--vldmode': dict(type=int, default=1, help='Valid mode'), 55 | '--rdymode': dict(type=int, default=1, help='Ready mode'), 56 | } 57 | 58 | # Create dut 59 | dut = SbDut('testbench', cmdline=True, extra_args=extra_args, 60 | trace=True, trace_type='vcd', default_main=True) 61 | 62 | # Set up inputs 63 | dut.use(sumi) 64 | dut.input('testbench.sv') 65 | 66 | # Verilator configuration 67 | dut.add('tool', 'verilator', 'task', 'compile', 'warningoff', 68 | ['WIDTHTRUNC', 'TIMESCALEMOD']) 69 | 70 | dut.build() 71 | 72 | return dut 73 | 74 | 75 | if __name__ == '__main__': 76 | main() 77 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ 3 | "setuptools >= 61.2", 4 | "setuptools_scm[toml] >= 6.2" 5 | ] 6 | build-backend = "setuptools.build_meta" 7 | 8 | [tool.setuptools_scm] 9 | # Presence of this section activates setuptools_scm, even though it's empty 10 | 11 | [project] 12 | name = "umi" 13 | authors = [{name = "Zero ASIC"}] 14 | description = "Universal Memory Interface (UMI)" 15 | readme = "README.md" 16 | urls = {Homepage = "https://github.com/zeroasiccorp/umi"} 17 | requires-python = ">= 3.8" 18 | license = {file = "LICENSE"} 19 | dependencies = [ 20 | "siliconcompiler>=0.27.0", 21 | "lambdalib>=0.2.10, <0.4.0" 22 | ] 23 | dynamic = [ 24 | "version" 25 | ] 26 | 27 | [tool.setuptools.dynamic] 28 | version = {attr = "umi.__version__"} 29 | 30 | [project.optional-dependencies] 31 | test = [ 32 | "switchboard-hw>=0.2.17", 33 | "flake8==7.2.0", 34 | "pytest==8.4.0", 35 | "pytest-xdist==3.7.0", 36 | "pytest-timeout==2.4.0" 37 | ] 38 | 39 | [tool.setuptools] 40 | include-package-data = true 41 | packages = [ 42 | "umi" 43 | ] 44 | 45 | [tool.check-wheel-contents] 46 | ignore = [ 47 | "W002" 48 | ] 49 | 50 | [tool.pytest.ini_options] 51 | markers = [ 52 | "switchboard: this test requires switchboard to run" 53 | ] 54 | testpaths = [ 55 | "tests", 56 | "umi/sumi/tests", 57 | "umi/lumi/tests" 58 | ] 59 | timeout = "300" 60 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import os 3 | 4 | 5 | @pytest.fixture(autouse=True) 6 | def test_wrapper(tmp_path): 7 | ''' 8 | Fixture that automatically runs each test in a test-specific temporary 9 | directory to avoid clutter. 10 | ''' 11 | 12 | topdir = os.getcwd() 13 | os.chdir(tmp_path) 14 | 15 | # Run the test. 16 | yield 17 | 18 | os.chdir(topdir) 19 | -------------------------------------------------------------------------------- /tests/test_lint.py: -------------------------------------------------------------------------------- 1 | from siliconcompiler import Chip 2 | from siliconcompiler.flows import lintflow 3 | import glob 4 | import pytest 5 | import umi 6 | import shutil 7 | from pathlib import Path 8 | 9 | 10 | @pytest.fixture 11 | def slang_chip(): 12 | chip = Chip('lint') 13 | chip.use(lintflow, tool='slang') 14 | 15 | chip.use(umi) 16 | chip.set('option', 'flow', 'lintflow') 17 | 18 | return chip 19 | 20 | 21 | @pytest.fixture 22 | def slang(): 23 | if shutil.which('slang') is None: 24 | pytest.skip('slang is not installed') 25 | 26 | 27 | def __filelist(): 28 | return glob.glob(str(Path(umi.__file__).parent / '**' / 'rtl' / '*.v')) 29 | 30 | 31 | @pytest.mark.parametrize('file', __filelist()) 32 | def test_lint_slang(slang_chip, file): 33 | slang_chip.set('option', 'entrypoint', Path(file).stem) 34 | 35 | if slang_chip.get('option', 'entrypoint') == 'umi_packet_merge_greedy': 36 | pytest.skip(reason='File is outdaded and will be cleaned up later') 37 | 38 | slang_chip.input(file) 39 | slang_chip.run() 40 | 41 | assert slang_chip.get('record', 'toolexitcode', step='lint', index='0') == 0 42 | -------------------------------------------------------------------------------- /umi/__init__.py: -------------------------------------------------------------------------------- 1 | from umi import sumi, lumi 2 | 3 | 4 | __version__ = "0.2.0" 5 | 6 | 7 | def setup(): 8 | return [ 9 | sumi.setup(), 10 | lumi.setup() 11 | ] 12 | -------------------------------------------------------------------------------- /umi/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import os 3 | import multiprocessing 4 | 5 | 6 | @pytest.fixture(autouse=True) 7 | def test_wrapper(tmp_path): 8 | ''' 9 | Fixture that automatically runs each test in a test-specific temporary 10 | directory to avoid clutter. 11 | ''' 12 | try: 13 | multiprocessing.set_start_method('fork') 14 | except RuntimeError: 15 | pass 16 | 17 | topdir = os.getcwd() 18 | os.chdir(tmp_path) 19 | 20 | # Run the test. 21 | yield 22 | 23 | os.chdir(topdir) 24 | 25 | 26 | def pytest_addoption(parser): 27 | parser.addoption("--seed", type=int, action="store", help="Provide a fixed seed") 28 | 29 | 30 | @pytest.fixture 31 | def random_seed(request): 32 | fixed_seed = request.config.getoption("--seed") 33 | if fixed_seed is not None: 34 | test_seed = fixed_seed 35 | else: 36 | test_seed = os.getpid() 37 | print(f'Random seed used: {test_seed}') 38 | yield test_seed 39 | print(f'Random seed used: {test_seed}') 40 | -------------------------------------------------------------------------------- /umi/lumi/__init__.py: -------------------------------------------------------------------------------- 1 | from siliconcompiler import Library 2 | from umi import sumi 3 | from lambdalib import auxlib, ramlib 4 | 5 | 6 | def setup(): 7 | lib = Library("lumi", package=("umi", "python://umi"), auto_enable=True) 8 | 9 | lib.add("option", "idir", "lumi/rtl") 10 | lib.add("option", "ydir", "lumi/rtl") 11 | 12 | lib.add("option", "idir", "utils/rtl") 13 | lib.add("option", "ydir", "utils/rtl") 14 | 15 | lib.use(sumi) 16 | 17 | lib.use(auxlib) 18 | lib.use(ramlib) 19 | 20 | return lib 21 | -------------------------------------------------------------------------------- /umi/lumi/rtl/lumi_regmap.vh: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2023 Zero ASIC Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * ---- 17 | * 18 | * Documentation: 19 | * - LUMI Register Map 20 | * 21 | ******************************************************************************/ 22 | 23 | // registers (addr[7:0]), 32bit aligned 24 | localparam LUMI_CTRL = 8'h00; // device configuration 25 | localparam LUMI_STATUS = 8'h04; // device status 26 | localparam LUMI_TXMODE = 8'h10; // tx operating mode 27 | localparam LUMI_RXMODE = 8'h14; // rx operating mode 28 | localparam LUMI_CRDTINIT = 8'h20; // Credit init value 29 | localparam LUMI_CRDTINTRVL = 8'h24; // Credit update interval 30 | localparam LUMI_REQCRDTSTALLCYC = 8'h30; // Cycle count of outstanding request transaction and credits are not available 31 | localparam LUMI_RESPCRDTSTALLCYC = 8'h34; // Cycle count of outstanding response transaction and credits are not available 32 | localparam LUMI_REQCRDTACTIVECYC = 8'h38; // Cycle count of outstanding request transaction and credits are available 33 | localparam LUMI_RESPCRDTACTIVECYC = 8'h3C; // Cycle count of outstanding response transaction and credits are available 34 | -------------------------------------------------------------------------------- /umi/lumi/testbench/config.vlt: -------------------------------------------------------------------------------- 1 | `verilator_config 2 | //lint_off -file "*umi/umi/rtl/umi_mem_agent*" 3 | lint_off -rule WIDTHEXPAND 4 | //lint_off -file "*lambdalib/ramlib/*" 5 | //lint_off -file "*lambdalib/stdlib/*" 6 | lint_off -file "*verilog-axi/rtl/*" 7 | //lint_off -rule LATCH 8 | //lint_off -rule UNOPTFLAT 9 | lint_off -rule WIDTHTRUNC 10 | //lint_off -rule SELRANGE 11 | lint_off -rule IMPLICIT 12 | lint_off -rule DECLFILENAME 13 | lint_off -rule PINCONNECTEMPTY 14 | lint_off -rule UNUSEDPARAM 15 | lint_off -rule UNUSEDSIGNAL 16 | lint_off -rule UNUSEDGENVAR 17 | lint_off -rule UNDRIVEN 18 | lint_off -rule BLKSEQ -file "*switchboard/switchboard/verilog/*" 19 | lint_off -rule GENUNNAMED 20 | -------------------------------------------------------------------------------- /umi/lumi/tests/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from switchboard import SbDut 3 | from umi import lumi 4 | from fasteners import InterProcessLock 5 | 6 | 7 | def pytest_collection_modifyitems(items): 8 | for item in items: 9 | if "lumi_dut" in getattr(item, "fixturenames", ()): 10 | item.add_marker("switchboard") 11 | pass 12 | 13 | 14 | @pytest.fixture 15 | def build_dir(pytestconfig): 16 | return pytestconfig.cache.mkdir('lumi_build') 17 | 18 | 19 | @pytest.fixture 20 | def lumi_dut(build_dir, request): 21 | 22 | dut = SbDut('testbench', default_main=True, trace=False) 23 | 24 | # dut = SbDut('testbench', cmdline=True, 25 | # default_main=True, trace=True, trace_type='vcd') 26 | 27 | dut.use(lumi) 28 | 29 | # Add testbench 30 | dut.input('lumi/testbench/testbench_lumi.sv', package='umi') 31 | 32 | # Verilator configuration 33 | dut.set('tool', 'verilator', 'task', 'compile', 'file', 'config', 'lumi/testbench/config.vlt', 34 | package='umi') 35 | 36 | # Build simulator 37 | dut.set('option', 'builddir', build_dir / lumi.__name__) 38 | with InterProcessLock(build_dir / f'{lumi.__name__}.lock'): 39 | # ensure build only happens once 40 | # https://github.com/pytest-dev/pytest-xdist/blob/v3.6.1/docs/how-to.rst#making-session-scoped-fixtures-execute-only-once 41 | dut.build(fast=True) 42 | 43 | yield dut 44 | 45 | dut.terminate() 46 | 47 | 48 | @pytest.fixture(params=("2d", "3d")) 49 | def chip_topo(request): 50 | return request.param 51 | -------------------------------------------------------------------------------- /umi/lumi/tests/test_lumi_ready.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2025 Zero ASIC 4 | # This code is licensed under Apache License 2.0 (see LICENSE for details) 5 | 6 | import multiprocessing 7 | import numpy as np 8 | from switchboard import SbDut, UmiTxRx, UmiCmd, random_umi_packet, umi_loopback 9 | from umi import lumi 10 | 11 | 12 | def gen_mergeable_umi_packets(num_bytes, size, opcode_arr, bytes_per_tx=16): 13 | 14 | packets = [] 15 | 16 | if (bytes_per_tx > 16): 17 | num_mergeable_packets = bytes_per_tx // 16 18 | else: 19 | num_mergeable_packets = 1 20 | 21 | for _ in range(num_bytes // bytes_per_tx): 22 | dstaddr = (2**8)*np.random.randint(2**32) 23 | srcaddr = (2**8)*np.random.randint(2**32) 24 | opcode = np.random.choice(opcode_arr) 25 | for _ in range(num_mergeable_packets): 26 | length = ((bytes_per_tx // num_mergeable_packets) >> size) - 1 27 | txp = random_umi_packet(opcode=opcode, dstaddr=dstaddr, 28 | srcaddr=srcaddr, size=size, len=length, 29 | eom=0, eof=0, max_bytes=16) 30 | packets.append(txp) 31 | cmd_len = (txp.cmd >> 8) & 0xFF 32 | cmd_size = (txp.cmd >> 5) & 0x07 33 | cmd_bytes = (2**cmd_size) * (cmd_len + 1) 34 | dstaddr = dstaddr + cmd_bytes 35 | srcaddr = srcaddr + cmd_bytes 36 | 37 | return packets 38 | 39 | 40 | def main(): 41 | 42 | multiprocessing.set_start_method('fork') 43 | 44 | dut = SbDut('testbench', default_main=True, trace=True) 45 | 46 | dut.use(lumi) 47 | 48 | # Add testbench 49 | dut.input('lumi/testbench/testbench_lumi_ready.sv', package='umi') 50 | 51 | # Verilator configuration 52 | dut.set('tool', 'verilator', 'task', 'compile', 'file', 'config', 'lumi/testbench/config.vlt', 53 | package='umi') 54 | 55 | dut.build() 56 | 57 | # launch the simulation 58 | dut.simulate( 59 | plusargs=[ 60 | ('valid_mode', 1), 61 | ('ready_mode', 1) 62 | ] 63 | ) 64 | 65 | packets_req = gen_mergeable_umi_packets(num_bytes=65536, 66 | size=0, 67 | opcode_arr=[UmiCmd.UMI_REQ_READ, 68 | UmiCmd.UMI_REQ_WRITE, 69 | UmiCmd.UMI_REQ_POSTED, 70 | UmiCmd.UMI_REQ_ATOMIC], 71 | bytes_per_tx=64) 72 | 73 | packets_resp = gen_mergeable_umi_packets(num_bytes=65536, 74 | size=0, 75 | opcode_arr=[UmiCmd.UMI_RESP_READ, 76 | UmiCmd.UMI_RESP_WRITE], 77 | bytes_per_tx=64) 78 | 79 | # instantiate TX and RX queues. note that these can be instantiated without 80 | # specifying a URI, in which case the URI can be specified later via the 81 | # "init" method 82 | 83 | req = UmiTxRx("umi_req_in.q", "umi_req_out.q", fresh=True) 84 | resp = UmiTxRx("umi_resp_in.q", "umi_resp_out.q", fresh=True) 85 | 86 | print("### Starting test ###") 87 | 88 | procs = [] 89 | 90 | procs.append(multiprocessing.Process(target=umi_loopback, args=(req, packets_req))) 91 | 92 | procs.append(multiprocessing.Process(target=umi_loopback, args=(resp, packets_resp))) 93 | 94 | for proc in procs: 95 | proc.start() 96 | 97 | for proc in procs: 98 | proc.join() 99 | 100 | 101 | if __name__ == '__main__': 102 | main() 103 | -------------------------------------------------------------------------------- /umi/sumi/__init__.py: -------------------------------------------------------------------------------- 1 | from siliconcompiler import Library 2 | from lambdalib import auxlib, ramlib, vectorlib 3 | 4 | 5 | def setup(): 6 | lib = Library("sumi", package=("umi", "python://umi"), auto_enable=True) 7 | 8 | lib.add("option", "idir", "sumi/rtl") 9 | lib.add("option", "ydir", "sumi/rtl") 10 | 11 | lib.add("option", "idir", "utils/rtl") 12 | lib.add("option", "ydir", "utils/rtl") 13 | 14 | lib.use(auxlib) 15 | lib.use(ramlib) 16 | lib.use(vectorlib) 17 | 18 | return lib 19 | -------------------------------------------------------------------------------- /umi/sumi/rtl/umi_arbiter.v: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2020 Zero ASIC Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * ---- 17 | * 18 | * Documentation: 19 | * - Dynamically configurable arbiter (fixed, roundrobin, reserve,...) 20 | * 21 | ******************************************************************************/ 22 | 23 | module umi_arbiter 24 | #(parameter N = 4, // number of inputs 25 | parameter TARGET = "DEFAULT" // SIM, ASIC, FPGA, ... 26 | ) 27 | (// controls 28 | input clk, 29 | input nreset, 30 | input [1:0] mode, // [00]=priority,[01]=roundrobin,[1x]=reserved 31 | input [N-1:0] mask, // 1 = disable request, 0 = enable request 32 | input [N-1:0] requests, // incoming requests 33 | output [N-1:0] grants // outgoing grants 34 | ); 35 | 36 | wire collision; 37 | reg [N-1:0] thermometer; 38 | wire [N-1:0] spec_requests; 39 | genvar i; 40 | 41 | // NOTE: The thermometer mask works correctly in case of a collision 42 | // that is followed by a single request from a masked source. 43 | // Consider, 4 requestors but only 0 and 1 are requesting: 44 | // cycle 0: req[0] = 1, req[1] = 1, grants[0] = 1, grants[1] = 0, collision = 1, therm = 4'b0000 45 | // cycle 1: req[0] = 0, req[1] = 1, grants[0] = 0, grants[1] = 1, collision = 0, therm = 4'b0001 46 | // cycle 2: req[0] = 1, req[1] = 0, grants[0] = 0, grants[1] = 0, collision = 1, therm = 4'b0001 47 | // cycle 3: req[0] = 1, req[1] = 0, grants[0] = 0, grants[1] = 0, collision = 1, therm = 4'b0011 48 | // cycle 4: req[0] = 1, req[1] = 0, grants[0] = 0, grants[1] = 0, collision = 1, therm = 4'b0111 49 | // cycle 5: req[0] = 1, req[1] = 0, grants[0] = 1, grants[1] = 0, collision = 0, therm = 4'b0000 50 | // Here, after cycle 0, requestor 0 was masked due to a collision with 51 | // requestor 1. When requestor 0 sends its second request with no other 52 | // requestors trying, it incurs a 3 cycle penalty for the thermometer to 53 | // fill up. While the 3 cycle penalty is detrimental to performance the 54 | // system does not hang. 55 | 56 | // Thermometer mask that gets hotter with every collision 57 | // wraps to zero when all ones 58 | generate if (N > 1) 59 | begin 60 | always @ (posedge clk or negedge nreset) 61 | if (~nreset) 62 | thermometer[N-1:0] <= {N{1'b0}}; 63 | else if(collision & (mode[1:0]==2'b10)) 64 | thermometer[N-1:0] <= (&thermometer[N-2:0]) ? {N{1'b0}} : {thermometer[N-2:0],1'b1}; 65 | end 66 | else 67 | begin 68 | always @ (posedge clk or negedge nreset) 69 | if (~nreset) 70 | thermometer[N-1:0] <= {N{1'b0}}; 71 | else 72 | thermometer[N-1:0] <= {N{1'b0}}; 73 | end 74 | endgenerate 75 | 76 | // 1. Create N rotated set of requests 77 | // 2. Feed requests into fixed priority encoders 78 | // double width needed for rotation 79 | assign spec_requests = ~mask[N-1:0] & 80 | ~thermometer[N-1:0] & 81 | requests[N-1:0]; 82 | 83 | // Priority Selection Using Masked Inputs 84 | umi_priority #(.N(N)) 85 | umi_priority(// Outputs 86 | .grants (grants[N-1:0]), 87 | // Inputs 88 | .requests (spec_requests[N-1:0])); 89 | 90 | // Detect collision on pushback 91 | assign collision = |(requests[N-1:0] & ~grants[N-1:0]); 92 | 93 | `ifdef VERILATOR 94 | assert property (@(posedge clk) $onehot0(grants)); 95 | `endif 96 | 97 | endmodule 98 | -------------------------------------------------------------------------------- /umi/sumi/rtl/umi_crossbar.v: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2020 Zero ASIC Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * ---- 17 | * 18 | * Documentation: 19 | * - Pipelined non-blocking NxN crossbar 20 | * - Input request vector is a concatenated vectors of inputs: 21 | * 22 | * [0] = input 0 requesting output 0 23 | * [1] = input 1 requesting output 0 24 | * [2] = input 2 requesting output 0 25 | * [N-1] = input N-1 requesting output 0 26 | * [N] = input 0 requesting output 1 27 | * [N+1] = input 1 requesting output 1 28 | * [N+2] = input 2 requesting output 1 29 | * [2*N-1] = input N-1 requesting output 1 30 | * ... 31 | * 32 | * Input to output paths are enabled through the [NxN] wide 'mask' input, 33 | * which follows ordering of the input valid convention shown above. 34 | * 35 | ******************************************************************************/ 36 | 37 | module umi_crossbar 38 | #(parameter TARGET = "DEFAULT", // implementation target 39 | parameter DW = 256, // UMI width 40 | parameter CW = 32, 41 | parameter AW = 64, 42 | parameter N = 2 // Total UMI ports 43 | ) 44 | (// controls 45 | input clk, 46 | input nreset, 47 | input [1:0] mode, // arbiter mode (0=fixed) 48 | input [N*N-1:0] mask, // arbiter mode (0=fixed) 49 | // Incoming UMI 50 | input [N*N-1:0] umi_in_request, 51 | input [N*CW-1:0] umi_in_cmd, 52 | input [N*AW-1:0] umi_in_dstaddr, 53 | input [N*AW-1:0] umi_in_srcaddr, 54 | input [N*DW-1:0] umi_in_data, 55 | output [N-1:0] umi_in_ready, 56 | // Outgoing UMI 57 | output [N-1:0] umi_out_valid, 58 | output [N*CW-1:0] umi_out_cmd, 59 | output [N*AW-1:0] umi_out_dstaddr, 60 | output [N*AW-1:0] umi_out_srcaddr, 61 | output [N*DW-1:0] umi_out_data, 62 | input [N-1:0] umi_out_ready 63 | ); 64 | 65 | wire [N*N-1:0] grants; 66 | reg [N-1:0] umi_ready; 67 | wire [N*N-1:0] umi_out_sel; 68 | genvar i; 69 | 70 | //############################## 71 | // Arbiters for all outputs 72 | //############################## 73 | 74 | for (i=0;i host) 45 | output cmd_read_resp, 46 | output cmd_write_resp, 47 | output cmd_user0_resp, 48 | output cmd_user1_resp, 49 | output cmd_future0_resp, 50 | output cmd_future1_resp, 51 | output cmd_link_resp, 52 | output cmd_atomic_add, 53 | 54 | // Atomic operations 55 | output cmd_atomic_and, 56 | output cmd_atomic_or, 57 | output cmd_atomic_xor, 58 | output cmd_atomic_max, 59 | output cmd_atomic_min, 60 | output cmd_atomic_maxu, 61 | output cmd_atomic_minu, 62 | output cmd_atomic_swap 63 | 64 | ); 65 | 66 | `include "umi_messages.vh" 67 | 68 | assign cmd_invalid = (command[7:0]==UMI_INVALID); 69 | 70 | // request/response/link 71 | assign cmd_request = command[0] & ~cmd_invalid; 72 | assign cmd_response = ~command[0] & ~cmd_invalid; 73 | 74 | // requests 75 | assign cmd_read = (command[3:0]==UMI_REQ_READ[3:0]); 76 | assign cmd_write = (command[3:0]==UMI_REQ_WRITE[3:0]); 77 | assign cmd_write_posted = (command[3:0]==UMI_REQ_POSTED[3:0]); 78 | assign cmd_rdma = (command[3:0]==UMI_REQ_RDMA[3:0]); 79 | assign cmd_atomic = (command[3:0]==UMI_REQ_ATOMIC[3:0]); 80 | assign cmd_user0 = (command[3:0]==UMI_REQ_USER0[3:0]); 81 | assign cmd_future0 = (command[3:0]==UMI_REQ_FUTURE0[3:0]); 82 | assign cmd_error = (command[7:0]==UMI_REQ_ERROR[7:0]); 83 | assign cmd_link = (command[7:0]==UMI_REQ_LINK[7:0]); 84 | // Response (device -> host) 85 | assign cmd_read_resp = (command[3:0]==UMI_RESP_READ[3:0]); 86 | assign cmd_write_resp = (command[3:0]==UMI_RESP_WRITE[3:0]); 87 | assign cmd_user0_resp = (command[3:0]==UMI_RESP_USER0[3:0]); 88 | assign cmd_user1_resp = (command[3:0]==UMI_RESP_USER1[3:0]); 89 | assign cmd_future0_resp = (command[3:0]==UMI_RESP_FUTURE0[3:0]); 90 | assign cmd_future1_resp = (command[3:0]==UMI_RESP_FUTURE1[3:0]); 91 | assign cmd_link_resp = (command[7:0]==UMI_RESP_LINK[7:0]); 92 | 93 | // read modify writes 94 | assign cmd_atomic_add = cmd_atomic & (command[15:8]==UMI_REQ_ATOMICADD); 95 | assign cmd_atomic_and = cmd_atomic & (command[15:8]==UMI_REQ_ATOMICAND); 96 | assign cmd_atomic_or = cmd_atomic & (command[15:8]==UMI_REQ_ATOMICOR); 97 | assign cmd_atomic_xor = cmd_atomic & (command[15:8]==UMI_REQ_ATOMICXOR); 98 | assign cmd_atomic_max = cmd_atomic & (command[15:8]==UMI_REQ_ATOMICMAX); 99 | assign cmd_atomic_min = cmd_atomic & (command[15:8]==UMI_REQ_ATOMICMIN); 100 | assign cmd_atomic_maxu = cmd_atomic & (command[15:8]==UMI_REQ_ATOMICMAXU); 101 | assign cmd_atomic_minu = cmd_atomic & (command[15:8]==UMI_REQ_ATOMICMINU); 102 | assign cmd_atomic_swap = cmd_atomic & (command[15:8]==UMI_REQ_ATOMICSWAP); 103 | 104 | endmodule // umi_decode 105 | -------------------------------------------------------------------------------- /umi/sumi/rtl/umi_demux.v: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2024 Zero ASIC Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * ---- 17 | * 18 | * Documentation: 19 | * 20 | * - Select signal selects output port 21 | * - Inputs broadcasted to all outputs 22 | * - Ready signal aggregated from otuputs 23 | * 24 | * Testing: 25 | * 26 | ******************************************************************************/ 27 | 28 | module umi_demux 29 | #( 30 | parameter M = 4, // number of outputs ports 31 | parameter DW = 128, // umi data width 32 | parameter CW = 32, // umi command width 33 | parameter AW = 64 // umi adress width 34 | ) 35 | (// Output selector 36 | input [M-1:0] select, 37 | // Incoming UMI 38 | input umi_in_valid, 39 | input [CW-1:0] umi_in_cmd, 40 | input [AW-1:0] umi_in_dstaddr, 41 | input [AW-1:0] umi_in_srcaddr, 42 | input [DW-1:0] umi_in_data, 43 | output umi_in_ready, 44 | // Outgoing UMI 45 | output [M-1:0] umi_out_valid, 46 | output [M*CW-1:0] umi_out_cmd, 47 | output [M*AW-1:0] umi_out_dstaddr, 48 | output [M*AW-1:0] umi_out_srcaddr, 49 | output [M*DW-1:0] umi_out_data, 50 | input [M-1:0] umi_out_ready 51 | ); 52 | 53 | // Valid signal 54 | assign umi_out_valid[M-1:0] = {M{umi_in_valid}} & select[M-1:0]; 55 | 56 | // Ready signal 57 | assign umi_in_ready = &(~select[M-1:0] | umi_out_ready[M-1:0]); 58 | 59 | // Broadcast packet 60 | assign umi_out_cmd[M*CW-1:0] = {M{umi_in_cmd[CW-1:0]}}; 61 | assign umi_out_dstaddr[M*AW-1:0] = {M{umi_in_dstaddr[AW-1:0]}}; 62 | assign umi_out_srcaddr[M*AW-1:0] = {M{umi_in_srcaddr[AW-1:0]}}; 63 | assign umi_out_data[M*DW-1:0] = {M{umi_in_data[DW-1:0]}}; 64 | 65 | endmodule 66 | -------------------------------------------------------------------------------- /umi/sumi/rtl/umi_fifo.v: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2020 Zero ASIC Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * ---- 17 | * 18 | * ##Documentation## 19 | * 20 | * - Asynchronous UMI FIFO 21 | * - Separate read and write clocks 22 | * 23 | ******************************************************************************/ 24 | 25 | module umi_fifo 26 | #(parameter TARGET = "DEFAULT", // implementation target 27 | parameter DEPTH = 4, // FIFO depth 28 | parameter AW = 64, // UMI width 29 | parameter CW = 32, // UMI width 30 | parameter DW = 256 // UMI width 31 | ) 32 | (// control/status signals 33 | input bypass, // bypass FIFO 34 | input chaosmode, // enable "random" fifo pushback 35 | output fifo_full, 36 | output fifo_empty, 37 | // Input 38 | input umi_in_clk, 39 | input umi_in_nreset, 40 | input umi_in_valid,//per byte valid signal 41 | input [CW-1:0] umi_in_cmd, 42 | input [AW-1:0] umi_in_dstaddr, 43 | input [AW-1:0] umi_in_srcaddr, 44 | input [DW-1:0] umi_in_data, 45 | output umi_in_ready, 46 | // Output 47 | input umi_out_clk, 48 | input umi_out_nreset, 49 | output umi_out_valid, 50 | output [CW-1:0] umi_out_cmd, 51 | output [AW-1:0] umi_out_dstaddr, 52 | output [AW-1:0] umi_out_srcaddr, 53 | output [DW-1:0] umi_out_data, 54 | input umi_out_ready, 55 | // Supplies 56 | input vdd, 57 | input vss 58 | ); 59 | 60 | // local state 61 | reg fifo_out_valid; 62 | reg [DW-1:0] fifo_out_data; 63 | 64 | // local wires 65 | wire umi_out_beat; 66 | wire fifo_read; 67 | wire fifo_write; 68 | wire [DW+AW+AW+CW-1:0] fifo_dout; 69 | wire fifo_in_ready; 70 | 71 | //################################# 72 | // UMI Control Logic 73 | //################################# 74 | 75 | // Read FIFO when ready (blocked inside fifo when empty) 76 | assign fifo_read = ~fifo_empty & umi_out_ready; 77 | 78 | // Write fifo when high (blocked inside fifo when full) 79 | assign fifo_write = ~fifo_full & umi_in_valid; 80 | 81 | // FIFO pushback 82 | assign fifo_in_ready = ~fifo_full; 83 | 84 | //################################# 85 | // Standard Dual Clock FIFO 86 | //################################# 87 | 88 | la_asyncfifo #(.DW(CW+AW+AW+DW), 89 | .DEPTH(DEPTH)) 90 | fifo (// Outputs 91 | .wr_full (fifo_full), 92 | .rd_dout (fifo_dout[DW+AW+AW+CW-1:0]), 93 | .rd_empty (fifo_empty), 94 | // Inputs 95 | .wr_clk (umi_in_clk), 96 | .wr_nreset (umi_in_nreset), 97 | .wr_din ({umi_in_data[DW-1:0],umi_in_srcaddr[AW-1:0],umi_in_dstaddr[AW-1:0],umi_in_cmd[CW-1:0]}), 98 | .wr_en (umi_in_valid), 99 | .wr_chaosmode (chaosmode), 100 | .rd_clk (umi_out_clk), 101 | .rd_nreset (umi_out_nreset), 102 | .rd_en (fifo_read), 103 | .vss (vss), 104 | .vdd (vdd), 105 | .ctrl (1'b0), 106 | .test (1'b0)); 107 | 108 | //################################# 109 | // FIFO Bypass 110 | //################################# 111 | 112 | assign umi_out_cmd[CW-1:0] = bypass ? umi_in_cmd[CW-1:0] : fifo_dout[CW-1:0]; 113 | assign umi_out_dstaddr[AW-1:0] = bypass ? umi_in_dstaddr[AW-1:0] : fifo_dout[CW+:AW]; 114 | assign umi_out_srcaddr[AW-1:0] = bypass ? umi_in_srcaddr[AW-1:0] : fifo_dout[CW+AW+:AW]; 115 | assign umi_out_data[DW-1:0] = bypass ? umi_in_data[DW-1:0] : fifo_dout[CW+AW+AW+:DW]; 116 | assign umi_out_valid = bypass ? umi_in_valid : ~fifo_empty; 117 | assign umi_in_ready = bypass ? umi_out_ready : fifo_in_ready; 118 | 119 | // debug signals 120 | assign umi_out_beat = umi_out_valid & umi_out_ready; 121 | 122 | endmodule // clink_fifo 123 | // Local Variables: 124 | // verilog-library-directories:(".") 125 | // End: 126 | -------------------------------------------------------------------------------- /umi/sumi/rtl/umi_isolate.v: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2020 Zero ASIC Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * ---- 17 | * 18 | * ##Documentation## 19 | * 20 | * - Power domain isolation buffers 21 | * 22 | ******************************************************************************/ 23 | 24 | module umi_isolate 25 | #(parameter CW = 32, // umi command width 26 | parameter AW = 64, // umi address width 27 | parameter DW = 64, // umi data width 28 | parameter ISO = 0 // 1 = enable input isolation 29 | ) 30 | ( 31 | input isolate, // 1=clamp inputs to 0 32 | // floating signals 33 | input umi_ready, 34 | input umi_valid, 35 | input [CW-1:0] umi_cmd, 36 | input [AW-1:0] umi_dstaddr, 37 | input [AW-1:0] umi_srcaddr, 38 | input [DW-1:0] umi_data, 39 | // clamped signals 40 | output umi_ready_iso, 41 | output umi_valid_iso, 42 | output [CW-1:0] umi_cmd_iso, 43 | output [AW-1:0] umi_dstaddr_iso, 44 | output [AW-1:0] umi_srcaddr_iso, 45 | output [DW-1:0] umi_data_iso 46 | ); 47 | 48 | generate 49 | if(ISO) 50 | begin : g0 51 | la_visolo #(.N(1)) 52 | i_ready (.in(umi_ready), 53 | .out(umi_ready_iso), 54 | .iso(isolate)); 55 | 56 | la_visolo #(.N(1)) 57 | i_valid (.in(umi_valid), 58 | .out(umi_valid_iso), 59 | .iso(isolate)); 60 | 61 | la_visolo #(.N(CW)) 62 | i_cmd (.in(umi_cmd[CW-1:0]), 63 | .out(umi_cmd_iso[CW-1:0]), 64 | .iso(isolate)); 65 | 66 | la_visolo #(.N(AW)) 67 | i_dstaddr (.in(umi_dstaddr[AW-1:0]), 68 | .out(umi_dstaddr_iso[AW-1:0]), 69 | .iso(isolate)); 70 | 71 | la_visolo #(.N(AW)) 72 | i_srcaddr (.in(umi_srcaddr[AW-1:0]), 73 | .out(umi_srcaddr_iso[AW-1:0]), 74 | .iso(isolate)); 75 | 76 | la_visolo #(.N(DW)) 77 | i_data (.in(umi_data[DW-1:0]), 78 | .out(umi_data_iso[DW-1:0]), 79 | .iso(isolate)); 80 | end 81 | else 82 | begin : g0 83 | assign umi_ready_iso = umi_ready; 84 | assign umi_valid_iso = umi_valid; 85 | assign umi_cmd_iso[CW-1:0] = umi_cmd[CW-1:0]; 86 | assign umi_dstaddr_iso[AW-1:0] = umi_dstaddr[AW-1:0]; 87 | assign umi_srcaddr_iso[AW-1:0] = umi_srcaddr[AW-1:0]; 88 | assign umi_data_iso[DW-1:0] = umi_data[DW-1:0]; 89 | end 90 | 91 | endgenerate 92 | 93 | endmodule 94 | -------------------------------------------------------------------------------- /umi/sumi/rtl/umi_messages.vh: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2020 Zero ASIC Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * ---- 17 | * 18 | * ##Documentation## 19 | * 20 | * - This file defines all UMI commands. 21 | * 22 | * 23 | ******************************************************************************/ 24 | 25 | // Requests (host -> device) 26 | localparam UMI_MAXSIZE = 1024; // max word size per transaction 27 | localparam UMI_MAXLEN = 256; // max word transfers per transaction 28 | 29 | // Invalid transaction indicator (cmd[7:0]) 30 | localparam UMI_INVALID = 8'h00; 31 | 32 | // Requests (host -> device) (cmd[7:0]) 33 | localparam UMI_REQ_READ = 5'h01; // read/load 34 | localparam UMI_REQ_WRITE = 5'h03; // write/store with ack 35 | localparam UMI_REQ_POSTED = 5'h05; // posted write 36 | localparam UMI_REQ_RDMA = 5'h07; // remote DMA command 37 | localparam UMI_REQ_ATOMIC = 5'h09; // alias for all atomics 38 | localparam UMI_REQ_USER0 = 5'h0B; // reserved for user 39 | localparam UMI_REQ_FUTURE0 = 5'h0D; // reserved fur future use 40 | localparam UMI_REQ_ERROR = 8'h0F; // reserved for error message 41 | localparam UMI_REQ_LINK = 8'h2F; // reserved for link ctrl 42 | 43 | // Response (device -> host) (cmd[7:0]) 44 | localparam UMI_RESP_READ = 5'h02; // response to read request 45 | localparam UMI_RESP_WRITE = 5'h04; // response (ack) from write request 46 | localparam UMI_RESP_USER0 = 5'h06; // signal write without ack 47 | localparam UMI_RESP_USER1 = 5'h08; // reserved for user 48 | localparam UMI_RESP_FUTURE0 = 5'h0A; // reserved for future use 49 | localparam UMI_RESP_FUTURE1 = 5'h0C; // reserved for future use 50 | localparam UMI_RESP_LINK = 8'h0E; // reserved for link ctrl 51 | 52 | // Atomic command decode (cmd[15:8]) 53 | localparam UMI_REQ_ATOMICADD = 8'h00; 54 | localparam UMI_REQ_ATOMICAND = 8'h01; 55 | localparam UMI_REQ_ATOMICOR = 8'h02; 56 | localparam UMI_REQ_ATOMICXOR = 8'h03; 57 | localparam UMI_REQ_ATOMICMAX = 8'h04; 58 | localparam UMI_REQ_ATOMICMIN = 8'h05; 59 | localparam UMI_REQ_ATOMICMAXU = 8'h06; 60 | localparam UMI_REQ_ATOMICMINU = 8'h07; 61 | localparam UMI_REQ_ATOMICSWAP = 8'h08; 62 | -------------------------------------------------------------------------------- /umi/sumi/rtl/umi_mux.v: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2024 Zero ASIC Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * ---- 17 | * 18 | * N:1 UMI transaction mux with arbiter and flow control. 19 | * 20 | ******************************************************************************/ 21 | 22 | module umi_mux 23 | #(parameter N = 2, // mumber of inputs 24 | parameter DW = 128, // umi data width 25 | parameter CW = 32, // umi command width 26 | parameter AW = 6 // umi address width 27 | ) 28 | (// controls 29 | input clk, 30 | input nreset, 31 | input [1:0] arbmode, // arbiter mode (0=fixed) 32 | input [N-1:0] arbmask, // arbiter mask (1=input is masked) 33 | // incoming UMI 34 | input [N-1:0] umi_in_valid, 35 | input [N*CW-1:0] umi_in_cmd, 36 | input [N*AW-1:0] umi_in_dstaddr, 37 | input [N*AW-1:0] umi_in_srcaddr, 38 | input [N*DW-1:0] umi_in_data, 39 | output reg [N-1:0] umi_in_ready, 40 | // outgoing UMI 41 | output umi_out_valid, 42 | output [CW-1:0] umi_out_cmd, 43 | output [AW-1:0] umi_out_dstaddr, 44 | output [AW-1:0] umi_out_srcaddr, 45 | output [DW-1:0] umi_out_data, 46 | input umi_out_ready 47 | ); 48 | 49 | wire [N-1:0] grants; 50 | 51 | //############################## 52 | // Valid Arbiter 53 | //############################## 54 | 55 | umi_arbiter #(.N(N)) 56 | umi_arbiter (// Outputs 57 | .grants (grants[N-1:0]), 58 | // Inputs 59 | .clk (clk), 60 | .nreset (nreset), 61 | .mode (arbmode[1:0]), 62 | .mask (arbmask[N-1:0]), 63 | .requests (umi_in_valid[N-1:0])); 64 | 65 | assign umi_out_valid = |grants[N-1:0]; 66 | 67 | //############################## 68 | // Ready 69 | //############################## 70 | 71 | 72 | // valid[j] | out_ready[j] | grant[j] | in_ready 73 | //------------------------------------------------ 74 | // 0 x x | 1 75 | // 1 0 x | 0 76 | // 1 1 0 | 0 77 | // 1 1 1 | 1 78 | 79 | integer j; 80 | always @(*) 81 | begin 82 | umi_in_ready[N-1:0] = {N{1'b1}}; 83 | for (j=0;j=1; j=j-1) 38 | begin : ipri 39 | assign mask[j] = |requests[j-1:0]; 40 | end 41 | 42 | // priority grant circuit 43 | assign grants[N-1:0] = requests[N-1:0] & ~mask[N-1:0]; 44 | 45 | endmodule // umi_priority 46 | -------------------------------------------------------------------------------- /umi/sumi/rtl/umi_splitter.v: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2020 Zero ASIC Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * ---- 17 | * 18 | * Documentation: 19 | * - Splits up traffic based on type. 20 | * 21 | ******************************************************************************/ 22 | 23 | 24 | module umi_splitter 25 | #(// standard parameters 26 | parameter AW = 64, 27 | parameter CW = 32, 28 | parameter DW = 256) 29 | (// UMI Input 30 | input umi_in_valid, 31 | input [CW-1:0] umi_in_cmd, 32 | input [AW-1:0] umi_in_dstaddr, 33 | input [AW-1:0] umi_in_srcaddr, 34 | input [DW-1:0] umi_in_data, 35 | output umi_in_ready, 36 | // UMI Output 37 | output umi_resp_out_valid, 38 | output [CW-1:0] umi_resp_out_cmd, 39 | output [AW-1:0] umi_resp_out_dstaddr, 40 | output [AW-1:0] umi_resp_out_srcaddr, 41 | output [DW-1:0] umi_resp_out_data, 42 | input umi_resp_out_ready, 43 | // UMI Output 44 | output umi_req_out_valid, 45 | output [CW-1:0] umi_req_out_cmd, 46 | output [AW-1:0] umi_req_out_dstaddr, 47 | output [AW-1:0] umi_req_out_srcaddr, 48 | output [DW-1:0] umi_req_out_data, 49 | input umi_req_out_ready 50 | ); 51 | 52 | /*AUTOWIRE*/ 53 | // Beginning of automatic wires (for undeclared instantiated-module outputs) 54 | wire cmd_request; 55 | wire cmd_response; 56 | // End of automatics 57 | 58 | //######################## 59 | // UNPACK INPUT 60 | //######################## 61 | 62 | wire [4:0] cmd_opcode; 63 | /* umi_decode AUTO_TEMPLATE( 64 | .cmd_request (cmd_request[]), 65 | .cmd_response (cmd_response[]), 66 | .command (umi_in_cmd[]), 67 | ..* (), 68 | );*/ 69 | umi_decode #(.CW(CW)) 70 | umi_decode(/*AUTOINST*/ 71 | // Outputs 72 | .cmd_invalid (), // Templated 73 | .cmd_request (cmd_request), // Templated 74 | .cmd_response (cmd_response), // Templated 75 | .cmd_read (), // Templated 76 | .cmd_write (), // Templated 77 | .cmd_write_posted (), // Templated 78 | .cmd_rdma (), // Templated 79 | .cmd_atomic (), // Templated 80 | .cmd_user0 (), // Templated 81 | .cmd_future0 (), // Templated 82 | .cmd_error (), // Templated 83 | .cmd_link (), // Templated 84 | .cmd_read_resp (), // Templated 85 | .cmd_write_resp (), // Templated 86 | .cmd_user0_resp (), // Templated 87 | .cmd_user1_resp (), // Templated 88 | .cmd_future0_resp (), // Templated 89 | .cmd_future1_resp (), // Templated 90 | .cmd_link_resp (), // Templated 91 | .cmd_atomic_add (), // Templated 92 | .cmd_atomic_and (), // Templated 93 | .cmd_atomic_or (), // Templated 94 | .cmd_atomic_xor (), // Templated 95 | .cmd_atomic_max (), // Templated 96 | .cmd_atomic_min (), // Templated 97 | .cmd_atomic_maxu (), // Templated 98 | .cmd_atomic_minu (), // Templated 99 | .cmd_atomic_swap (), // Templated 100 | // Inputs 101 | .command (umi_in_cmd[CW-1:0])); // Templated 102 | 103 | // Detect Packet type (request or response) 104 | assign umi_resp_out_valid = umi_in_valid & cmd_response; 105 | assign umi_req_out_valid = umi_in_valid & cmd_request; 106 | 107 | // Broadcasting packet 108 | assign umi_resp_out_cmd[CW-1:0] = umi_in_cmd[CW-1:0]; 109 | assign umi_resp_out_dstaddr[AW-1:0] = umi_in_dstaddr[AW-1:0]; 110 | assign umi_resp_out_srcaddr[AW-1:0] = umi_in_srcaddr[AW-1:0]; 111 | assign umi_resp_out_data[DW-1:0] = umi_in_data[DW-1:0]; 112 | 113 | assign umi_req_out_cmd[CW-1:0] = umi_in_cmd[CW-1:0]; 114 | assign umi_req_out_dstaddr[AW-1:0] = umi_in_dstaddr[AW-1:0]; 115 | assign umi_req_out_srcaddr[AW-1:0] = umi_in_srcaddr[AW-1:0]; 116 | assign umi_req_out_data[DW-1:0] = umi_in_data[DW-1:0]; 117 | 118 | // Globally blocking ready implementation 119 | assign umi_in_ready = ~(umi_resp_out_valid & ~umi_resp_out_ready) & 120 | ~(umi_req_out_valid & ~umi_req_out_ready); 121 | 122 | endmodule // umi_splitter 123 | -------------------------------------------------------------------------------- /umi/sumi/rtl/umi_unpack.v: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2020 Zero ASIC Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * ---- 17 | * 18 | * ##Documentation## 19 | * 20 | * - Unpacks 32b command into separate ctrl fields 21 | * 22 | ******************************************************************************/ 23 | 24 | module umi_unpack 25 | #(parameter CW = 32) 26 | ( 27 | // Input packet 28 | input [CW-1:0] packet_cmd, 29 | 30 | // output fields 31 | output [4:0] cmd_opcode, 32 | output [2:0] cmd_size, 33 | output [7:0] cmd_len, 34 | output [7:0] cmd_atype, 35 | output [3:0] cmd_qos, 36 | output [1:0] cmd_prot, 37 | output cmd_eom, 38 | output cmd_eof, 39 | output cmd_ex, 40 | output [1:0] cmd_user, 41 | output [23:0] cmd_user_extended, 42 | output [1:0] cmd_err, 43 | output [4:0] cmd_hostid 44 | ); 45 | 46 | `include "umi_messages.vh" 47 | 48 | // data field unpacker 49 | wire cmd_request; 50 | wire cmd_response; 51 | wire cmd_atomic; 52 | wire cmd_error; 53 | wire cmd_link; 54 | wire cmd_link_resp; 55 | 56 | /*umi_decode AUTO_TEMPLATE( 57 | .cmd_error (cmd_error[]), 58 | .cmd_request (cmd_request[]), 59 | .cmd_response (cmd_response[]), 60 | .cmd_atomic (cmd_atomic[]), 61 | .cmd_link\(.*\) (cmd_link\1[]), 62 | .command (packet_cmd[]), 63 | .cmd_.* (), 64 | );*/ 65 | 66 | umi_decode #(.CW(CW)) 67 | umi_decode(/*AUTOINST*/ 68 | // Outputs 69 | .cmd_invalid (), // Templated 70 | .cmd_request (cmd_request), // Templated 71 | .cmd_response (cmd_response), // Templated 72 | .cmd_read (), // Templated 73 | .cmd_write (), // Templated 74 | .cmd_write_posted (), // Templated 75 | .cmd_rdma (), // Templated 76 | .cmd_atomic (cmd_atomic), // Templated 77 | .cmd_user0 (), // Templated 78 | .cmd_future0 (), // Templated 79 | .cmd_error (cmd_error), // Templated 80 | .cmd_link (cmd_link), // Templated 81 | .cmd_read_resp (), // Templated 82 | .cmd_write_resp (), // Templated 83 | .cmd_user0_resp (), // Templated 84 | .cmd_user1_resp (), // Templated 85 | .cmd_future0_resp (), // Templated 86 | .cmd_future1_resp (), // Templated 87 | .cmd_link_resp (cmd_link_resp), // Templated 88 | .cmd_atomic_add (), // Templated 89 | .cmd_atomic_and (), // Templated 90 | .cmd_atomic_or (), // Templated 91 | .cmd_atomic_xor (), // Templated 92 | .cmd_atomic_max (), // Templated 93 | .cmd_atomic_min (), // Templated 94 | .cmd_atomic_maxu (), // Templated 95 | .cmd_atomic_minu (), // Templated 96 | .cmd_atomic_swap (), // Templated 97 | // Inputs 98 | .command (packet_cmd[CW-1:0])); // Templated 99 | 100 | // Command fields - TODO: should we qualify these with the command type? 101 | assign cmd_opcode[4:0] = packet_cmd[4:0]; 102 | assign cmd_size[2:0] = packet_cmd[7:5]; // Ignore for error and link 103 | assign cmd_len[7:0] = cmd_atomic ? 8'd0 : packet_cmd[15:8]; // Ignore for error and link 104 | assign cmd_atype[7:0] = packet_cmd[15:8]; 105 | assign cmd_qos[3:0] = packet_cmd[19:16];// Ignore for link 106 | assign cmd_prot[1:0] = packet_cmd[21:20];// Ignore for link 107 | assign cmd_eom = packet_cmd[22]; 108 | assign cmd_eof = packet_cmd[23]; // Ignore for error and responses 109 | assign cmd_ex = packet_cmd[24]; // Ignore for error and responses 110 | assign cmd_hostid[4:0] = packet_cmd[31:27]; 111 | assign cmd_user[1:0] = packet_cmd[26:25]; 112 | assign cmd_err[1:0] = cmd_response ? packet_cmd[26:25] : 2'h0; 113 | 114 | assign cmd_user_extended[23:0] = packet_cmd[31:8]; 115 | 116 | endmodule // umi_unpack 117 | -------------------------------------------------------------------------------- /umi/sumi/testbench/config.vlt: -------------------------------------------------------------------------------- 1 | `verilator_config 2 | //lint_off -file "*umi/umi/rtl/umi_mem_agent*" 3 | lint_off -rule WIDTHEXPAND 4 | //lint_off -file "*lambdalib/ramlib/*" 5 | //lint_off -file "*lambdalib/stdlib/*" 6 | lint_off -file "*verilog-axi/rtl/*" 7 | //lint_off -rule LATCH 8 | //lint_off -rule UNOPTFLAT 9 | //lint_off -rule WIDTHTRUNC 10 | //lint_off -rule SELRANGE 11 | lint_off -rule IMPLICIT 12 | lint_off -rule DECLFILENAME 13 | lint_off -rule PINCONNECTEMPTY 14 | lint_off -rule UNUSEDPARAM 15 | lint_off -rule UNUSEDSIGNAL 16 | lint_off -rule UNUSEDGENVAR 17 | lint_off -rule UNDRIVEN 18 | lint_off -rule BLKSEQ -file "*switchboard/switchboard/verilog/*" 19 | lint_off -rule GENUNNAMED 20 | -------------------------------------------------------------------------------- /umi/sumi/testbench/cpp/umi_testbench.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "Vumi_testbench.h" 7 | #include "verilated.h" 8 | 9 | // quit flag set by SIGINT signal handler to gracefully clean up and close VCD 10 | // file when simulation is quit. 11 | volatile sig_atomic_t quit = 0; 12 | 13 | void signal_handler(int signum) { 14 | quit = 1; 15 | } 16 | 17 | void step(Vumi_testbench *top) { 18 | top->eval(); 19 | Verilated::timeInc(1); 20 | } 21 | 22 | int main(int argc, char **argv, char **env) 23 | { 24 | Verilated::commandArgs(argc, argv); 25 | 26 | #ifdef TRACE 27 | Verilated::traceEverOn(true); 28 | #endif 29 | 30 | Vumi_testbench *top = new Vumi_testbench; 31 | 32 | signal(SIGINT, signal_handler); 33 | 34 | // reset 35 | top->nreset = 1; 36 | step(top); 37 | top->nreset = 0; 38 | step(top); 39 | top->nreset = 1; 40 | step(top); 41 | 42 | // main loop 43 | top->clk = 0; 44 | step(top); 45 | while (!Verilated::gotFinish() && !quit) { 46 | // update logic 47 | top->clk ^= 1; 48 | step(top); 49 | } 50 | 51 | top->final(); 52 | delete top; 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /umi/sumi/testbench/dut_umi_fifo.v: -------------------------------------------------------------------------------- 1 | module dut_umi_fifo 2 | #(parameter TARGET = "DEFAULT", // synthesis target 3 | parameter MONITOR = 1, // turn on umi monitor 4 | parameter NUMI = 1, // number of umi interfaces 5 | parameter NCLK = 1, // number of clk pins 6 | parameter NCTRL = 1, // number of ctrl pins 7 | parameter NSTATUS = 1, // number of status pins 8 | // for development 9 | parameter CW = 32, // umi width 10 | parameter AW = 64, // umi width 11 | parameter DW = 512, // umi width 12 | parameter DEPTH = 4 // fifo depth 13 | ) 14 | (// generic control interface 15 | input nreset, // common async active low reset 16 | input [NCLK-1:0] clk, // generic set of clocks 17 | input go, // go dut, go! 18 | output error, //dut error 19 | output done, // dut done 20 | input [NCTRL-1:0] ctrl, // generic control vector (optional) 21 | output [NSTATUS-1:0] status, // generic status vector (optional) 22 | // umi interfaces 23 | input [NUMI-1:0] umi_in_clk, 24 | input [NUMI-1:0] umi_in_nreset, 25 | input [NUMI-1:0] umi_in_valid, 26 | input [NUMI*CW-1:0] umi_in_cmd, 27 | input [NUMI*AW-1:0] umi_in_dstaddr, 28 | input [NUMI*AW-1:0] umi_in_srcaddr, 29 | input [NUMI*DW-1:0] umi_in_data, 30 | output [NUMI-1:0] umi_in_ready, 31 | input [NUMI-1:0] umi_out_clk, 32 | input [NUMI-1:0] umi_out_nreset, 33 | output [NUMI-1:0] umi_out_valid, 34 | output [NUMI*CW-1:0] umi_out_cmd, 35 | output [NUMI*AW-1:0] umi_out_dstaddr, 36 | output [NUMI*AW-1:0] umi_out_srcaddr, 37 | output [NUMI*DW-1:0] umi_out_data, 38 | input [NUMI-1:0] umi_out_ready 39 | ); 40 | 41 | // Local wires 42 | reg slowclk; 43 | wire fifo_empty; 44 | wire fifo_full; 45 | 46 | /*AUTOINPUT*/ 47 | /*AUTOWIRE*/ 48 | 49 | //################################# 50 | //# HOST 51 | //################################# 52 | 53 | /* umi_fifo AUTO_TEMPLATE( 54 | .chaosmode (1'b0), 55 | );*/ 56 | umi_fifo #(.CW(CW), 57 | .AW(AW), 58 | .DW(DW), 59 | .DEPTH(DEPTH), 60 | .TARGET(TARGET)) 61 | umi_fifo (.bypass (1'b0), 62 | .vdd (1'b1), 63 | .vss (1'b0), 64 | /*AUTOINST*/ 65 | // Outputs 66 | .fifo_full (fifo_full), 67 | .fifo_empty (fifo_empty), 68 | .umi_in_ready (umi_in_ready), 69 | .umi_out_valid (umi_out_valid), 70 | .umi_out_cmd (umi_out_cmd[CW-1:0]), 71 | .umi_out_dstaddr (umi_out_dstaddr[AW-1:0]), 72 | .umi_out_srcaddr (umi_out_srcaddr[AW-1:0]), 73 | .umi_out_data (umi_out_data[DW-1:0]), 74 | // Inputs 75 | .chaosmode (1'b0), // Templated 76 | .umi_in_clk (umi_in_clk), 77 | .umi_in_nreset (umi_in_nreset), 78 | .umi_in_valid (umi_in_valid), 79 | .umi_in_cmd (umi_in_cmd[CW-1:0]), 80 | .umi_in_dstaddr (umi_in_dstaddr[AW-1:0]), 81 | .umi_in_srcaddr (umi_in_srcaddr[AW-1:0]), 82 | .umi_in_data (umi_in_data[DW-1:0]), 83 | .umi_out_clk (umi_out_clk), 84 | .umi_out_nreset (umi_out_nreset), 85 | .umi_out_ready (umi_out_ready)); 86 | 87 | endmodule // testbench 88 | // Local Variables: 89 | // verilog-library-directories:("../rtl") 90 | // End: 91 | -------------------------------------------------------------------------------- /umi/sumi/testbench/dut_umi_fifo_flex.v: -------------------------------------------------------------------------------- 1 | module dut_umi_fifo_flex 2 | #(parameter TARGET = "DEFAULT", // synthesis target 3 | parameter BYPASS = 0, 4 | parameter MONITOR = 1, // turn on umi monitor 5 | parameter NUMI = 1, // number of umi interfaces 6 | parameter NCLK = 1, // number of clk pins 7 | parameter NCTRL = 1, // number of ctrl pins 8 | parameter NSTATUS = 1, // number of status pins 9 | // for development 10 | parameter CW = 32, // umi width 11 | parameter AW = 64, // umi width 12 | parameter IDW = 512, // umi width 13 | parameter ODW = 512, // umi width 14 | parameter DEPTH = 4 // fifo depth 15 | ) 16 | (// generic control interface 17 | input nreset, // common async active low reset 18 | input [NCLK-1:0] clk, // generic set of clocks 19 | input go, // go dut, go! 20 | output error, //dut error 21 | output done, // dut done 22 | input [NCTRL-1:0] ctrl, // generic control vector (optional) 23 | output [NSTATUS-1:0] status, // generic status vector (optional) 24 | input bypass, 25 | // umi interfaces 26 | input [NUMI-1:0] umi_in_clk, 27 | input [NUMI-1:0] umi_in_nreset, 28 | input [NUMI-1:0] umi_in_valid, 29 | input [NUMI*CW-1:0] umi_in_cmd, 30 | input [NUMI*AW-1:0] umi_in_dstaddr, 31 | input [NUMI*AW-1:0] umi_in_srcaddr, 32 | input [NUMI*IDW-1:0] umi_in_data, 33 | output [NUMI-1:0] umi_in_ready, 34 | input [NUMI-1:0] umi_out_clk, 35 | input [NUMI-1:0] umi_out_nreset, 36 | output [NUMI-1:0] umi_out_valid, 37 | output [NUMI*CW-1:0] umi_out_cmd, 38 | output [NUMI*AW-1:0] umi_out_dstaddr, 39 | output [NUMI*AW-1:0] umi_out_srcaddr, 40 | output [NUMI*ODW-1:0] umi_out_data, 41 | input [NUMI-1:0] umi_out_ready 42 | ); 43 | 44 | // Local wires 45 | wire fifo_empty; 46 | wire fifo_full; 47 | 48 | /*AUTOINPUT*/ 49 | /*AUTOWIRE*/ 50 | 51 | //################################# 52 | //# HOST 53 | //################################# 54 | 55 | /* umi_fifo_flex AUTO_TEMPLATE( 56 | .chaosmode (1'b0), 57 | );*/ 58 | umi_fifo_flex #(.CW(CW), 59 | .AW(AW), 60 | .IDW(IDW), 61 | .ODW(ODW), 62 | .DEPTH(DEPTH), 63 | .TARGET(TARGET), 64 | .BYPASS(BYPASS)) 65 | umi_fifo_flex (.bypass (bypass), 66 | .vdd (1'b1), 67 | .vss (1'b0), 68 | /*AUTOINST*/ 69 | // Outputs 70 | .fifo_full (fifo_full), 71 | .fifo_empty (fifo_empty), 72 | .umi_in_ready (umi_in_ready), 73 | .umi_out_valid (umi_out_valid), 74 | .umi_out_cmd (umi_out_cmd[CW-1:0]), 75 | .umi_out_dstaddr (umi_out_dstaddr[AW-1:0]), 76 | .umi_out_srcaddr (umi_out_srcaddr[AW-1:0]), 77 | .umi_out_data (umi_out_data[ODW-1:0]), 78 | // Inputs 79 | .chaosmode (1'b0), // Templated 80 | .umi_in_clk (umi_in_clk), 81 | .umi_in_nreset (umi_in_nreset), 82 | .umi_in_valid (umi_in_valid), 83 | .umi_in_cmd (umi_in_cmd[CW-1:0]), 84 | .umi_in_dstaddr (umi_in_dstaddr[AW-1:0]), 85 | .umi_in_srcaddr (umi_in_srcaddr[AW-1:0]), 86 | .umi_in_data (umi_in_data[IDW-1:0]), 87 | .umi_out_clk (umi_out_clk), 88 | .umi_out_nreset (umi_out_nreset), 89 | .umi_out_ready (umi_out_ready)); 90 | 91 | endmodule // testbench 92 | // Local Variables: 93 | // verilog-library-directories:("../rtl") 94 | // End: 95 | -------------------------------------------------------------------------------- /umi/sumi/testbench/testbench_demux.sv: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2024 Zero ASIC Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * ---- 17 | * 18 | * Documentation: 19 | * - Simple umi demux testbench 20 | * 21 | ******************************************************************************/ 22 | 23 | module testbench ( 24 | `ifdef VERILATOR 25 | input clk 26 | `endif 27 | ); 28 | 29 | `include "switchboard.vh" 30 | 31 | localparam M = 4; 32 | localparam DW = 256; 33 | localparam CW = 32; 34 | localparam AW = 64; 35 | 36 | localparam PERIOD_CLK = 10; 37 | 38 | `ifndef VERILATOR 39 | // Generate clock for non verilator sim tools 40 | reg clk; 41 | 42 | initial 43 | clk = 1'b0; 44 | always #(PERIOD_CLK/2) clk = ~clk; 45 | `endif 46 | 47 | // Initialize UMI 48 | integer valid_mode, ready_mode; 49 | 50 | initial begin 51 | /* verilator lint_off IGNOREDRETURN */ 52 | if (!$value$plusargs("valid_mode=%d", valid_mode)) begin 53 | valid_mode = 2; // default if not provided as a plusarg 54 | end 55 | 56 | if (!$value$plusargs("ready_mode=%d", ready_mode)) begin 57 | ready_mode = 2; // default if not provided as a plusarg 58 | end 59 | /* verilator lint_on IGNOREDRETURN */ 60 | end 61 | 62 | wire [M-1:0] select; 63 | 64 | wire umi_in_valid; 65 | wire [CW-1:0] umi_in_cmd; 66 | wire [AW-1:0] umi_in_dstaddr; 67 | wire [AW-1:0] umi_in_srcaddr; 68 | wire [DW-1:0] umi_in_data; 69 | wire umi_in_ready; 70 | 71 | wire [M-1:0] umi_out_valid; 72 | wire [M*CW-1:0] umi_out_cmd; 73 | wire [M*AW-1:0] umi_out_dstaddr; 74 | wire [M*AW-1:0] umi_out_srcaddr; 75 | wire [M*DW-1:0] umi_out_data; 76 | wire [M-1:0] umi_out_ready; 77 | 78 | /////////////////////////////////////////// 79 | // Host side umi agents 80 | /////////////////////////////////////////// 81 | 82 | genvar i; 83 | 84 | queue_to_umi_sim #( 85 | .VALID_MODE_DEFAULT (2), 86 | .DW (DW) 87 | ) umi_rx_i ( 88 | .clk (clk), 89 | 90 | .valid (umi_in_valid), 91 | .cmd (umi_in_cmd), 92 | .dstaddr (umi_in_dstaddr), 93 | .srcaddr (umi_in_srcaddr), 94 | .data (umi_in_data), 95 | .ready (umi_in_ready) 96 | ); 97 | 98 | assign select = {{(M-1){1'b0}}, 1'b1}<= maxrange): 90 | tempval = tempval - maxrange 91 | elif (operation == 1): 92 | tempval = origdata & atomicdata 93 | elif (operation == 2): 94 | tempval = origdata | atomicdata 95 | elif (operation == 3): 96 | tempval = origdata ^ atomicdata 97 | elif (operation == 4): 98 | if (origdata & (maxrange >> 1)): 99 | origdata = int(origdata) - int(maxrange) 100 | else: 101 | origdata = int(origdata) 102 | if (atomicdata & (maxrange >> 1)): 103 | atomicdata = int(atomicdata) - int(maxrange) 104 | else: 105 | atomicdata = int(atomicdata) 106 | tempval = origdata if (origdata > atomicdata) else atomicdata 107 | elif (operation == 5): 108 | if (origdata & (maxrange >> 1)): 109 | origdata = int(origdata) - int(maxrange) 110 | else: 111 | origdata = int(origdata) 112 | if (atomicdata & (maxrange >> 1)): 113 | atomicdata = int(atomicdata) - int(maxrange) 114 | else: 115 | atomicdata = int(atomicdata) 116 | tempval = atomicdata if (origdata > atomicdata) else origdata 117 | elif (operation == 6): 118 | tempval = origdata if (origdata > atomicdata) else atomicdata 119 | elif (operation == 7): 120 | tempval = atomicdata if (origdata > atomicdata) else origdata 121 | elif (operation == 8): 122 | tempval = atomicdata 123 | else: 124 | tempval = atomicdata 125 | 126 | return tempval 127 | 128 | return setup 129 | -------------------------------------------------------------------------------- /umi/sumi/tests/test_crossbar.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2024 Zero ASIC 4 | # This code is licensed under Apache License 2.0 (see LICENSE for details) 5 | 6 | import pytest 7 | import multiprocessing 8 | from switchboard import UmiTxRx, delete_queue 9 | 10 | 11 | def test_crossbar(sumi_dut, umi_send, sb_umi_valid_mode, sb_umi_ready_mode): 12 | n = 100 13 | ports = 4 14 | for x in range(ports): 15 | delete_queue(f'rtl2client_{x}.q') 16 | delete_queue(f'client2rtl_{x}.q') 17 | delete_queue(f'tee_{x}.q') 18 | 19 | # launch the simulation 20 | sumi_dut.simulate( 21 | plusargs=['trace', ('PORTS', ports), 22 | ('valid_mode', sb_umi_valid_mode), 23 | ('ready_mode', sb_umi_ready_mode)]) 24 | 25 | # instantiate TX and RX queues. note that these can be instantiated without 26 | # specifying a URI, in which case the URI can be specified later via the 27 | # "init" method 28 | 29 | umi = [UmiTxRx('', f'rtl2client_{x}.q') for x in range(ports)] 30 | tee = [UmiTxRx('', f'tee_{x}.q') for x in range(ports)] 31 | 32 | print("### Starting test ###") 33 | recv_queue = [[[] for i in range(n)] for j in range(ports)] 34 | send_queue = [[[] for i in range(n)] for j in range(ports)] 35 | 36 | procs = [] 37 | for x in range(ports): 38 | procs.append(multiprocessing.Process(target=umi_send, 39 | args=(x, n, ports,))) 40 | 41 | for proc in procs: 42 | proc.start() 43 | 44 | nrecv = 0 45 | nsend = 0 46 | while (nrecv < ports*n) or (nsend < ports*n): 47 | for i in range(ports): 48 | rxp = umi[i].recv(blocking=False) 49 | if rxp is not None: 50 | if nrecv >= ports*n: 51 | print(f'Unexpected packet received {nrecv}') 52 | raise Exception(f'Unexpected packet received {nrecv}') 53 | else: 54 | recv_src = (rxp.srcaddr >> 40) 55 | print(f"port {i} receiving srcaddr: 0x{rxp.srcaddr:08x} " 56 | f"dstaddr: 0x{rxp.dstaddr:08x} src: {recv_src} #{nrecv}") 57 | recv_queue[recv_src][i].append(rxp) 58 | nrecv += 1 59 | 60 | for i in range(ports): 61 | txp = tee[i].recv(blocking=False) 62 | if txp is not None: 63 | if nsend >= ports*n: 64 | raise Exception('Unexpected packet sent') 65 | else: 66 | send_dst = (txp.dstaddr >> 40) 67 | send_queue[i][send_dst].append(txp) 68 | nsend += 1 69 | 70 | # join running processes 71 | for proc in procs: 72 | proc.join() 73 | 74 | for i in range(ports): 75 | for j in range(ports): 76 | if len(send_queue[i][j]) != len(recv_queue[i][j]): 77 | print(f"packets sent: {len(send_queue[i][j])} packets received: {len(recv_queue[i][j])}") 78 | assert len(send_queue[i][j]) == len(recv_queue[i][j]) 79 | for txp, rxp in zip(send_queue[i][j], recv_queue[i][j]): 80 | assert txp == rxp 81 | print(f"compared {len(recv_queue[i][j])} packets from port {i} to port {j}") 82 | 83 | 84 | if __name__ == '__main__': 85 | pytest.main(['-s', '-q', __file__]) 86 | -------------------------------------------------------------------------------- /umi/sumi/tests/test_demux.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2024 Zero ASIC 4 | # This code is licensed under Apache License 2.0 (see LICENSE for details) 5 | 6 | import pytest 7 | import multiprocessing 8 | from switchboard import UmiTxRx, delete_queue 9 | 10 | 11 | def test_demux(sumi_dut, umi_send, sb_umi_valid_mode, sb_umi_ready_mode): 12 | n = 4000 # Number of transactions to be sent to each demux input port 13 | in_ports = 1 # Number of input ports. Fixed to 1 for demux 14 | out_ports = 4 # Number of output ports. Must match testbench 15 | 16 | for x in range(in_ports): 17 | delete_queue(f'client2rtl_{x}.q') 18 | delete_queue(f'tee_{x}.q') 19 | 20 | # Instantiate TX and RX queues 21 | umi = [UmiTxRx('', f'rtl2client_{x}.q', fresh=True) for x in range(out_ports)] 22 | tee = [UmiTxRx('', f'tee_{x}.q') for x in range(in_ports)] 23 | 24 | # launch the simulation 25 | sumi_dut.simulate( 26 | plusargs=[('valid_mode', sb_umi_valid_mode), 27 | ('ready_mode', sb_umi_ready_mode)]) 28 | 29 | print("### Starting test ###") 30 | 31 | send_proc = multiprocessing.Process(target=umi_send, 32 | args=(0, n, out_ports,)) 33 | 34 | send_proc.start() 35 | 36 | recv_queue = [[] for i in range(out_ports)] 37 | send_queue = [[] for i in range(out_ports)] 38 | 39 | nrecv = 0 40 | nsend = 0 41 | while (nrecv < in_ports*n) or (nsend < in_ports*n): 42 | for i in range(out_ports): 43 | rxp = umi[i].recv(blocking=False) 44 | if rxp is not None: 45 | if nrecv >= in_ports*n: 46 | print(f'Unexpected packet received {nrecv}') 47 | raise Exception(f'Unexpected packet received {nrecv}') 48 | else: 49 | recv_src = (rxp.srcaddr >> 40) 50 | print(f"port {i} receiving srcaddr: 0x{rxp.srcaddr:08x} " 51 | f"dstaddr: 0x{rxp.dstaddr:08x} src: {recv_src} #{nrecv}") 52 | recv_queue[i].append(rxp) 53 | nrecv += 1 54 | 55 | for i in range(in_ports): 56 | txp = tee[i].recv(blocking=False) 57 | if txp is not None: 58 | if nsend >= in_ports*n: 59 | raise Exception('Unexpected packet sent') 60 | else: 61 | send_dst = (txp.dstaddr >> 40) 62 | send_queue[send_dst].append(txp) 63 | nsend += 1 64 | 65 | # join Tx sender 66 | send_proc.join() 67 | 68 | for i in range(out_ports): 69 | if len(send_queue[i]) != len(recv_queue[i]): 70 | print(f"packets sent: {len(send_queue[i])} packets received: {len(recv_queue[i])}") 71 | assert len(send_queue[i]) == len(recv_queue[i]) 72 | for txp, rxp in zip(send_queue[i], recv_queue[i]): 73 | assert txp == rxp 74 | print(f"Received {len(recv_queue[i])} packets at port {i}") 75 | 76 | 77 | if __name__ == '__main__': 78 | pytest.main(['-s', '-q', __file__]) 79 | -------------------------------------------------------------------------------- /umi/sumi/tests/test_fifo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2024 Zero ASIC 4 | # This code is licensed under Apache License 2.0 (see LICENSE for details) 5 | 6 | import pytest 7 | import random 8 | import numpy as np 9 | from switchboard import UmiTxRx 10 | 11 | 12 | def test_fifo(sumi_dut, random_seed, sb_umi_valid_mode, sb_umi_ready_mode): 13 | 14 | random.seed(random_seed) 15 | np.random.seed(random_seed) 16 | 17 | # launch the simulation 18 | sumi_dut.simulate(plusargs=[('valid_mode', sb_umi_valid_mode), ('ready_mode', sb_umi_ready_mode)]) 19 | 20 | # instantiate TX and RX queues. note that these can be instantiated without 21 | # specifying a URI, in which case the URI can be specified later via the 22 | # "init" method 23 | 24 | host = UmiTxRx("host2dut_0.q", "dut2host_0.q", fresh=True) 25 | 26 | print("### Starting test ###") 27 | 28 | for _ in range(100): 29 | # length should not cross the DW boundary - umi_mem_agent limitation 30 | length = np.random.randint(0, 15) 31 | dst_addr = 32*random.randrange(2**(10-5)-1) # sb limitation - should align to bus width 32 | src_addr = 32*random.randrange(2**(10-5)-1) 33 | data8 = np.random.randint(0, 255, size=length, dtype=np.uint8) 34 | print(f"umi writing {length+1} bytes to addr 0x{dst_addr:08x}") 35 | host.write(dst_addr, data8, srcaddr=src_addr) 36 | print(f"umi read from addr 0x{dst_addr:08x}") 37 | val8 = host.read(dst_addr, length, np.uint8, srcaddr=src_addr) 38 | if ~((val8 == data8).all()): 39 | print(f"ERROR umi read from addr 0x{dst_addr:08x}") 40 | print(f"Expected: {data8}") 41 | print(f"Actual: {val8}") 42 | assert (val8 == data8).all() 43 | 44 | 45 | if __name__ == '__main__': 46 | pytest.main(['-s', '-q', __file__]) 47 | -------------------------------------------------------------------------------- /umi/sumi/tests/test_fifo_flex.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2024 Zero ASIC 4 | # This code is licensed under Apache License 2.0 (see LICENSE for details) 5 | 6 | import pytest 7 | import random 8 | import numpy as np 9 | from switchboard import UmiTxRx 10 | 11 | 12 | def test_fifo_flex(sumi_dut, random_seed, sb_umi_valid_mode, sb_umi_ready_mode): 13 | 14 | random.seed(random_seed) 15 | np.random.seed(random_seed) 16 | 17 | # launch the simulation 18 | sumi_dut.simulate(plusargs=[('valid_mode', sb_umi_valid_mode), ('ready_mode', sb_umi_ready_mode)]) 19 | 20 | # instantiate TX and RX queues. note that these can be instantiated without 21 | # specifying a URI, in which case the URI can be specified later via the 22 | # "init" method 23 | 24 | host = UmiTxRx("host2dut_0.q", "dut2host_0.q", fresh=True) 25 | 26 | print("### Starting test ###") 27 | 28 | for count in range(1000): 29 | # length should not cross the DW boundary - umi_mem_agent limitation 30 | length = np.random.randint(0, 255) 31 | dst_addr = 32*random.randrange(2**(10-5)-1) # sb limitation - should align to bus width 32 | src_addr = 32*random.randrange(2**(10-5)-1) 33 | data8 = np.random.randint(0, 255, size=length, dtype=np.uint8) 34 | print(f"[{count}] umi writing {length} bytes to addr 0x{dst_addr:08x}") 35 | host.write(dst_addr, data8, srcaddr=src_addr, max_bytes=16) 36 | print(f"[{count}] umi read from addr 0x{dst_addr:08x}") 37 | val8 = host.read(dst_addr, length, np.uint8, srcaddr=src_addr, max_bytes=16) 38 | if ~((val8 == data8).all()): 39 | print(f"ERROR umi read from addr 0x{dst_addr:08x}") 40 | print(f"Expected: {data8}") 41 | print(f"Actual: {val8}") 42 | assert (val8 == data8).all() 43 | 44 | 45 | if __name__ == '__main__': 46 | pytest.main(['-s', '-q', __file__]) 47 | -------------------------------------------------------------------------------- /umi/sumi/tests/test_isolate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2024 Zero ASIC 4 | # This code is licensed under Apache License 2.0 (see LICENSE for details) 5 | 6 | import pytest 7 | from switchboard import UmiTxRx, umi_loopback 8 | 9 | 10 | def test_isolate(sumi_dut, sb_umi_valid_mode, sb_umi_ready_mode): 11 | 12 | # launch the simulation 13 | sumi_dut.simulate(plusargs=[('valid_mode', sb_umi_valid_mode), ('ready_mode', sb_umi_ready_mode)]) 14 | 15 | # instantiate TX and RX queues. note that these can be instantiated without 16 | # specifying a URI, in which case the URI can be specified later via the 17 | # "init" method 18 | 19 | host = UmiTxRx("host2dut_0.q", "dut2host_0.q", fresh=True) 20 | 21 | print("### Starting test ###") 22 | 23 | umi_loopback(host, 1000, max_bytes=32) 24 | 25 | 26 | if __name__ == '__main__': 27 | pytest.main(['-s', '-q', __file__]) 28 | -------------------------------------------------------------------------------- /umi/sumi/tests/test_mem_agent.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2023 Zero ASIC 4 | # This code is licensed under Apache License 2.0 (see LICENSE for details) 5 | 6 | import pytest 7 | import numpy as np 8 | from switchboard import UmiTxRx 9 | 10 | 11 | def test_mem_agent(sumi_dut, apply_atomic, random_seed, sb_umi_valid_mode, sb_umi_ready_mode): 12 | 13 | np.random.seed(random_seed) 14 | 15 | # launch the simulation 16 | sumi_dut.simulate(plusargs=[('valid_mode', sb_umi_valid_mode), ('ready_mode', sb_umi_ready_mode)]) 17 | 18 | # instantiate TX and RX queues. note that these can be instantiated without 19 | # specifying a URI, in which case the URI can be specified later via the 20 | # "init" method 21 | 22 | host = UmiTxRx("host2dut_0.q", "dut2host_0.q", fresh=True) 23 | 24 | print("### Starting test ###") 25 | 26 | avail_datatype = [np.uint8, np.uint16, np.uint32] 27 | 28 | # un-aligned accesses 29 | for _ in range(100): 30 | addr = np.random.randint(0, 512) 31 | # length should not cross the DW boundary - umi_mem_agent limitation 32 | length = np.random.randint(0, 256) 33 | wordindexer = np.random.choice([0, 1, 2]) 34 | maxrange = 2**(8*(2**wordindexer)) 35 | data = np.random.randint(0, maxrange, size=(length+1), dtype=avail_datatype[wordindexer]) 36 | addr = addr*(2**wordindexer) & 0x1FF 37 | 38 | print(f"umi writing {length+1} words of type {avail_datatype[wordindexer]} to addr 0x{addr:08x}") 39 | host.write(addr, data) 40 | atomicopcode = np.random.randint(0, 9) 41 | atomicdata = np.random.randint(0, 256, dtype=avail_datatype[wordindexer]) 42 | print(f"umi atomic opcode: {atomicopcode} of type {avail_datatype[wordindexer]} to addr 0x{addr:08x}") 43 | atomicval = host.atomic(addr, atomicdata, atomicopcode) 44 | if not (atomicval == data[0]): 45 | print(f"ERROR umi atomic from addr 0x{addr:08x} expected {data[0]} actual {atomicval}") 46 | assert (atomicval == data[0]) 47 | temp_data = apply_atomic(data[0], atomicdata, atomicopcode, maxrange) 48 | data[0] = np.array(temp_data).astype(avail_datatype[wordindexer]) 49 | 50 | print(f"umi read from addr 0x{addr:08x}") 51 | val = host.read(addr, length+1, dtype=avail_datatype[wordindexer]) 52 | if not (np.array_equal(val, data)): 53 | print(f"ERROR umi read from addr 0x{addr:08x} expected {data} actual {val}") 54 | assert (np.array_equal(val, data)) 55 | 56 | 57 | if __name__ == '__main__': 58 | pytest.main(['-s', '-q', __file__]) 59 | -------------------------------------------------------------------------------- /umi/sumi/tests/test_mux.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2024 Zero ASIC 4 | # This code is licensed under Apache License 2.0 (see LICENSE for details) 5 | 6 | import pytest 7 | import multiprocessing 8 | from switchboard import UmiTxRx, random_umi_packet, delete_queue 9 | 10 | 11 | def test_mux(sumi_dut, umi_send, sb_umi_valid_mode, sb_umi_ready_mode): 12 | n = 1000 # Number of transactions to be sent to each mux input port 13 | in_ports = 4 # Number of input ports. Must match testbench 14 | out_ports = 1 # Number of output ports. Fixed to 1 for mux 15 | 16 | for x in range(in_ports): 17 | delete_queue(f'client2rtl_{x}.q') 18 | delete_queue(f'tee_{x}.q') 19 | 20 | # Instantiate TX and RX queues 21 | umi = [UmiTxRx('', f'rtl2client_{x}.q', fresh=True) for x in range(out_ports)] 22 | tee = [UmiTxRx('', f'tee_{x}.q') for x in range(in_ports)] 23 | 24 | # launch the simulation 25 | sumi_dut.simulate( 26 | plusargs=[('valid_mode', sb_umi_valid_mode), 27 | ('ready_mode', sb_umi_ready_mode)]) 28 | 29 | print("### Starting test ###") 30 | 31 | send_procs = [] 32 | 33 | for x in range(in_ports): 34 | send_procs.append(multiprocessing.Process(target=umi_send, 35 | args=(x, n, out_ports,))) 36 | 37 | for proc in send_procs: 38 | proc.start() 39 | 40 | recv_queue = [[] for i in range(in_ports)] 41 | send_queue = [[] for i in range(in_ports)] 42 | 43 | nrecv = 0 44 | nsend = 0 45 | while (nrecv < in_ports*n) or (nsend < in_ports*n): 46 | for i in range(out_ports): 47 | rxp = umi[i].recv(blocking=False) 48 | if rxp is not None: 49 | if nrecv >= in_ports*n: 50 | print(f'Unexpected packet received {nrecv}') 51 | raise Exception(f'Unexpected packet received {nrecv}') 52 | else: 53 | recv_src = (rxp.srcaddr >> 40) 54 | print(f"port {i} receiving srcaddr: 0x{rxp.srcaddr:08x} " 55 | f"dstaddr: 0x{rxp.dstaddr:08x} src: {recv_src} #{nrecv}") 56 | recv_queue[recv_src].append(rxp) 57 | nrecv += 1 58 | 59 | for i in range(in_ports): 60 | txp = tee[i].recv(blocking=False) 61 | if txp is not None: 62 | if nsend >= in_ports*n: 63 | raise Exception('Unexpected packet sent') 64 | else: 65 | send_queue[i].append(txp) 66 | nsend += 1 67 | 68 | # join Tx senders 69 | for proc in send_procs: 70 | proc.join() 71 | 72 | for i in range(in_ports): 73 | if len(send_queue[i]) != len(recv_queue[i]): 74 | print(f"packets sent: {len(send_queue[i])} packets received: {len(recv_queue[i])}") 75 | assert len(send_queue[i]) == len(recv_queue[i]) 76 | for txp, rxp in zip(send_queue[i], recv_queue[i]): 77 | assert txp == rxp 78 | print(f"Received {len(recv_queue[i])} packets at port {i}") 79 | 80 | 81 | @pytest.mark.skip(reason="Must only be run when evaluating performance using waveforms") 82 | def test_round_robin_arb(sumi_dut): 83 | ''' 84 | This test is used to get an initial idea of the performance impact of 85 | the arbitration scheme present in the mux. With the thermometer based 86 | round robin scheme this test shows a performance penalty of up to 4 87 | cycles for a thermometer masked transaction. This test must be run with 88 | the waveform enabled. 89 | ''' 90 | 91 | # Instantiate TX and RX queues 92 | inq = [UmiTxRx(f'client2rtl_{x}.q', '', fresh=True) for x in range(2)] 93 | 94 | # launch the simulation 95 | sumi_dut.simulate( 96 | plusargs=[('valid_mode', 1), 97 | ('ready_mode', 1)]) 98 | 99 | txp = random_umi_packet() 100 | print(f"Sending cmd: 0x{txp.cmd:08x} " 101 | f"srcaddr: 0x{txp.srcaddr:08x} dstaddr: 0x{txp.dstaddr:08x}") 102 | # send the packet to both simulation and local queues 103 | inq[0].send(txp) 104 | inq[1].send(txp) 105 | inq[0].send(txp) 106 | 107 | 108 | if __name__ == '__main__': 109 | pytest.main(['-s', '-q', __file__]) 110 | -------------------------------------------------------------------------------- /umi/sumi/tests/test_regif.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2023 Zero ASIC 4 | # This code is licensed under Apache License 2.0 (see LICENSE for details) 5 | 6 | import pytest 7 | import numpy as np 8 | from switchboard import UmiTxRx 9 | 10 | 11 | def test_regif(sumi_dut, random_seed, sb_umi_valid_mode, sb_umi_ready_mode): 12 | 13 | np.random.seed(random_seed) 14 | 15 | # launch the simulation 16 | sumi_dut.simulate(plusargs=[('valid_mode', sb_umi_valid_mode), 17 | ('ready_mode', sb_umi_ready_mode)]) 18 | 19 | # instantiate TX and RX queues. note that these can be instantiated without 20 | # specifying a URI, in which case the URI can be specified later via the 21 | # "init" method 22 | 23 | host = UmiTxRx("host2dut_0.q", "dut2host_0.q", fresh=True) 24 | 25 | print("### Starting test ###") 26 | 27 | # regif accesses are all 32b wide and aligned 28 | for _ in range(10): 29 | addr = np.random.randint(0, 16) * 4 30 | # length should not cross the DW boundary - umi_mem_agent limitation 31 | data = np.random.randint(2**32, dtype=np.uint32) 32 | 33 | print(f"umi writing 0x{data:08x} to addr 0x{addr:08x}") 34 | host.write(addr, data) 35 | print(f"umi read from addr 0x{addr:08x}") 36 | val = host.read(addr, np.uint32) 37 | if not (val == data): 38 | print(f"ERROR umi read from addr 0x{addr:08x} expected {data} actual {val}") 39 | assert (val == data) 40 | 41 | 42 | if __name__ == '__main__': 43 | pytest.main(['-s', '-q', __file__]) 44 | -------------------------------------------------------------------------------- /umi/sumi/tests/test_switch.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2024 Zero ASIC 4 | # This code is licensed under Apache License 2.0 (see LICENSE for details) 5 | 6 | import pytest 7 | import multiprocessing 8 | from switchboard import UmiTxRx, delete_queue 9 | 10 | 11 | def test_switch(sumi_dut, umi_send, sb_umi_valid_mode, sb_umi_ready_mode): 12 | n = 1000 # Number of transactions to be sent to each switch input port 13 | in_ports = 4 # Number of input ports. Must match testbench 14 | out_ports = 2 # Number of output ports. Must match testbench 15 | 16 | for x in range(in_ports): 17 | delete_queue(f'client2rtl_{x}.q') 18 | delete_queue(f'tee_{x}.q') 19 | 20 | # Instantiate TX and RX queues 21 | umi = [UmiTxRx('', f'rtl2client_{x}.q', fresh=True) for x in range(out_ports)] 22 | tee = [UmiTxRx('', f'tee_{x}.q') for x in range(in_ports)] 23 | 24 | # launch the simulation 25 | sumi_dut.simulate( 26 | plusargs=[('valid_mode', sb_umi_valid_mode), 27 | ('ready_mode', sb_umi_ready_mode)]) 28 | 29 | print("### Starting test ###") 30 | 31 | procs = [] 32 | for x in range(in_ports): 33 | procs.append(multiprocessing.Process(target=umi_send, 34 | args=(x, n, out_ports,))) 35 | 36 | for proc in procs: 37 | proc.start() 38 | 39 | recv_queue = [[[] for i in range(out_ports)] for j in range(in_ports)] 40 | send_queue = [[[] for i in range(out_ports)] for j in range(in_ports)] 41 | 42 | nrecv = 0 43 | nsend = 0 44 | while (nrecv < in_ports*n) or (nsend < in_ports*n): 45 | for i in range(out_ports): 46 | rxp = umi[i].recv(blocking=False) 47 | if rxp is not None: 48 | if nrecv >= in_ports*n: 49 | print(f'Unexpected packet received {nrecv}') 50 | raise Exception(f'Unexpected packet received {nrecv}') 51 | else: 52 | recv_src = (rxp.srcaddr >> 40) 53 | print(f"port {i} receiving srcaddr: 0x{rxp.srcaddr:08x} " 54 | f"dstaddr: 0x{rxp.dstaddr:08x} src: {recv_src} #{nrecv}") 55 | recv_queue[recv_src][i].append(rxp) 56 | nrecv += 1 57 | 58 | for i in range(in_ports): 59 | txp = tee[i].recv(blocking=False) 60 | if txp is not None: 61 | if nsend >= in_ports*n: 62 | raise Exception('Unexpected packet sent') 63 | else: 64 | send_dst = (txp.dstaddr >> 40) 65 | send_queue[i][send_dst].append(txp) 66 | nsend += 1 67 | 68 | # join running processes 69 | for proc in procs: 70 | proc.join() 71 | 72 | for i in range(in_ports): 73 | for j in range(out_ports): 74 | if len(send_queue[i][j]) != len(recv_queue[i][j]): 75 | print(f"packets sent: {len(send_queue[i][j])} packets received: {len(recv_queue[i][j])}") 76 | assert len(send_queue[i][j]) == len(recv_queue[i][j]) 77 | for txp, rxp in zip(send_queue[i][j], recv_queue[i][j]): 78 | assert txp == rxp 79 | print(f"compared {len(recv_queue[i][j])} packets from port {i} to port {j}") 80 | 81 | 82 | if __name__ == '__main__': 83 | pytest.main(['-s', '-q', __file__]) 84 | -------------------------------------------------------------------------------- /umi/sumi/tests/test_umi_ram.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2023 Zero ASIC 4 | # This code is licensed under Apache License 2.0 (see LICENSE for details) 5 | 6 | import pytest 7 | import numpy as np 8 | from switchboard import UmiTxRx 9 | 10 | 11 | def test_umi_ram(sumi_dut, apply_atomic, random_seed, sb_umi_valid_mode, sb_umi_ready_mode): 12 | 13 | ports = 5 # Number of input ports of umi_ram. Must match testbench 14 | n = 100 # Number of reads, atomic txns and writes each from the umi_ram 15 | 16 | np.random.seed(random_seed) 17 | 18 | # launch the simulation 19 | sumi_dut.simulate( 20 | plusargs=[('valid_mode', sb_umi_valid_mode), 21 | ('ready_mode', sb_umi_ready_mode)]) 22 | 23 | # instantiate TX and RX queues. note that these can be instantiated without 24 | # specifying a URI, in which case the URI can be specified later via the 25 | # "init" method 26 | 27 | host = [UmiTxRx(f'host2dut_{x}.q', f'dut2host_{x}.q', fresh=True) for x in range(ports)] 28 | 29 | print("### Starting test ###") 30 | 31 | avail_datatype = [np.uint8, np.uint16, np.uint32] 32 | 33 | # un-aligned accesses 34 | for _ in range(n): 35 | psel = np.random.choice([0, 1, 2, 3, 4]) 36 | srcaddr = 1 << (40 + psel) 37 | addr = np.random.randint(0, 512) 38 | # length should not cross the DW boundary - umi_mem_agent limitation 39 | length = np.random.randint(0, 256) 40 | wordindexer = np.random.choice([0, 1, 2]) 41 | maxrange = 2**(8*(2**wordindexer)) 42 | data = np.random.randint(0, maxrange, size=(length+1), dtype=avail_datatype[wordindexer]) 43 | addr = addr*(2**wordindexer) & 0x1FF 44 | 45 | print(f"umi{psel} writing {length+1} words of type {avail_datatype[wordindexer]}" 46 | f"to addr 0x{addr:08x}") 47 | host[psel].write(addr, data, srcaddr=srcaddr) 48 | 49 | psel = np.random.choice([0, 1, 2, 3, 4]) 50 | srcaddr = 1 << (40 + psel) 51 | atomicopcode = np.random.randint(0, 9) 52 | atomicdata = np.random.randint(0, 256, dtype=avail_datatype[wordindexer]) 53 | print(f"umi{psel} atomic opcode: {atomicopcode} of type {avail_datatype[wordindexer]}" 54 | f"to addr 0x{addr:08x}") 55 | atomicval = host[psel].atomic(addr, atomicdata, atomicopcode, srcaddr=srcaddr) 56 | if not (atomicval == data[0]): 57 | print(f"ERROR umi atomic from addr 0x{addr:08x} expected {data[0]} actual {atomicval}") 58 | assert (atomicval == data[0]) 59 | temp_data = apply_atomic(data[0], atomicdata, atomicopcode, maxrange) 60 | data[0] = np.array(temp_data).astype(avail_datatype[wordindexer]) 61 | 62 | psel = np.random.choice([0, 1, 2, 3, 4]) 63 | srcaddr = 1 << (40 + psel) 64 | print(f"umi{psel} read from addr 0x{addr:08x}") 65 | val = host[psel].read(addr, length+1, srcaddr=srcaddr, dtype=avail_datatype[wordindexer]) 66 | if not (np.array_equal(val, data)): 67 | print(f"ERROR umi read from addr 0x{addr:08x} expected {data} actual {val}") 68 | assert (np.array_equal(val, data)) 69 | 70 | 71 | if __name__ == '__main__': 72 | pytest.main(['-s', '-q', __file__]) 73 | -------------------------------------------------------------------------------- /umi/utils/rtl/README.md: -------------------------------------------------------------------------------- 1 | # Ebrick Address Remap 2 | 3 | ## Functionality 4 | This module remaps UMI transactions across different memory regions. The current address map dictates that the memory region attached to each CLINK/UMI is 1 TiB. Hence, the address bits [39:0] of a UMI transaction are used to address regions within a UMI device attached to a CLINK port. Bits [55:40] are ID bits used to identify the appropriate CLINK/UMI device on the efabric and to route transactions to it. Bits [63:56] are reserved. 5 | 6 | The module performs 2 functions. It allows remapping UMI transactions going to a UMI device to be redirected to a different device and it allows addresses within a certain range to be offsetted by a base address. 7 | 8 | In order to accomplish the remapping, it accepts NMAPS input mappings from one device address to another. In the mapping, the bits being remapped are denoted by old_row_col_address and the bits being mapped to are denoted by new_row_col_address. The ID bits of dstaddr of an incoming transaction on the input UMI port are compared to the NMAPS different old_row_col_address and if a match is found, bits [55:40] of the dstaddr are replaced by the corresponding new_row_col_address. 9 | 10 | The offset is accomplished by comparing the dstaddr of an incoming UMI packet to a lower and upper bound. If the dstaddr lies within the bounds (inclusive), then an offset is added to the dstaddr of the incoming UMI packet before it is sent out. Currently, only a single offset is permitted. 11 | 12 | The offset mechanism gets priority over remapping. So if an incoming UMI packet contains a dstaddr that can be both offsetted and remapped, only the offsetted address will be sent out. 13 | 14 | ## Limitations 15 | Any transactions to local devices (within the ebrick issuing the transaction) that use the current devices chipid in bits [55:40] are maintained as is even if a mapping exists. There exist two ways for a device to access its own local memory region, bits [55:40] can be set to the devices own chipid or they can be set to 0. To be clear, transactions to local memory regions that set bits [55:40] to 0 can still be remapped. Only local transactions that use chipid in bits [55:40] cannot be remapped. This allows the host to maintain access to critical local infrastructure including the memory that contains the various address mappings. 16 | 17 | ## For software developers 18 | The primary intention of the remap feature is to allow a host to access main memory that exists at a different CLINK/UMI region. Current software for RISCV hosts tends to boot from address such as 0x8000_0000. The software would need to be rewritten in order to work with the ebrick/efabric address map. This module allows a developer to remap and offset an outgoing transaction and thus boot from a device that might not be a part of the local memory region. After boot is complete, it is expected that the developer will reverse the remapping. 19 | -------------------------------------------------------------------------------- /umi/utils/rtl/tl-uh.vh: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2023 Zero ASIC Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * ---- 17 | * 18 | * Documentation: 19 | * - TileLink Uncached Heavyweight (TL-UH) definitions 20 | * 21 | ******************************************************************************/ 22 | 23 | // Opcode for channel A 24 | `define TL_OP_Get 3'd4 25 | `define TL_OP_PutFullData 3'd0 26 | `define TL_OP_PutPartialData 3'd1 27 | `define TL_OP_ArithmeticData 3'd2 28 | `define TL_OP_LogicalData 3'd3 29 | `define TL_OP_Intent 3'd5 30 | 31 | // Opcode for channel D 32 | `define TL_OP_AccessAck 3'd0 33 | `define TL_OP_AccessAckData 3'd1 34 | `define TL_OP_HintAck 3'd2 35 | 36 | // Param for arithmetic data 37 | `define TL_PA_MIN 3'd0 38 | `define TL_PA_MAX 3'd1 39 | `define TL_PA_MINU 3'd2 40 | `define TL_PA_MAXU 3'd3 41 | `define TL_PA_ADD 3'd4 42 | 43 | // Param for logical data 44 | `define TL_PL_XOR 3'd0 45 | `define TL_PL_OR 3'd1 46 | `define TL_PL_AND 3'd2 47 | `define TL_PL_SWAP 3'd3 48 | -------------------------------------------------------------------------------- /umi/utils/rtl/umi_address_remap.v: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2023 Zero ASIC Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * ---- 17 | * 18 | * Documentation: 19 | * This module remaps UMI transactions across different memory regions. 20 | * The module introduces a new parameter called IDSB which denotes the bit at 21 | * which the chip ID starts in a umi address. This parameter can also be 22 | * considered as the per ebrick/clink address space. For example, in a 64 bit 23 | * address space, IDSB is 40 - along with IDW = 16, this mean the chip ID 24 | * resides between IDSB + IDW - 1 to IDSB i.e. bits 55:40. Additionally, one 25 | * can also infer that the addresses within a clink/umi connected device is 26 | * 40 bits wide i.e. a memory space of 1 TiB. 27 | 28 | * Limitation: 29 | * NMAPS parameterization is incomplete 30 | * Currently NMAPS < 8 will fail and NMAPS > 8 will not have the desired effect 31 | * beyond 8 remappings. 32 | * 33 | ******************************************************************************/ 34 | 35 | `default_nettype wire 36 | 37 | module umi_address_remap #( 38 | parameter CW = 32, // command width 39 | parameter AW = 64, // address width 40 | parameter DW = 128, // data width 41 | parameter IDW = 16, // id width 42 | parameter IDSB = 40, // id start bit - bit 40 in 64 bit address space 43 | parameter NMAPS = 8 // number of remaps 44 | ) 45 | ( 46 | input [IDW-1:0] chipid, 47 | 48 | input [IDW*NMAPS-1:0] old_row_col_address, 49 | input [IDW*NMAPS-1:0] new_row_col_address, 50 | 51 | input [AW-1:0] set_dstaddress_low, 52 | input [AW-1:0] set_dstaddress_high, 53 | input [AW-1:0] set_dstaddress_offset, 54 | 55 | input umi_in_valid, 56 | input [CW-1:0] umi_in_cmd, 57 | input [AW-1:0] umi_in_dstaddr, 58 | input [AW-1:0] umi_in_srcaddr, 59 | input [DW-1:0] umi_in_data, 60 | output umi_in_ready, 61 | 62 | output umi_out_valid, 63 | output [CW-1:0] umi_out_cmd, 64 | output [AW-1:0] umi_out_dstaddr, 65 | output [AW-1:0] umi_out_srcaddr, 66 | output [DW-1:0] umi_out_data, 67 | input umi_out_ready 68 | ); 69 | 70 | // Address remapping 71 | wire [IDW-1:0] old_row_col_address_unpack [0:NMAPS-1]; 72 | wire [IDW-1:0] new_row_col_address_unpack [0:NMAPS-1]; 73 | 74 | genvar i; 75 | generate 76 | for (i = 0; i < NMAPS; i = i + 1) begin 77 | assign old_row_col_address_unpack[i] = old_row_col_address[(IDW*(i+1))-1 : (IDW*i)]; 78 | assign new_row_col_address_unpack[i] = new_row_col_address[(IDW*(i+1))-1 : (IDW*i)]; 79 | end 80 | endgenerate 81 | 82 | reg [IDW-1:0] dstaddr_upper; 83 | 84 | always @(*) begin 85 | // FIXME: Parameterize this 86 | case (umi_in_dstaddr[(IDSB+IDW-1):IDSB]) 87 | old_row_col_address_unpack[0] : dstaddr_upper = new_row_col_address_unpack[0]; 88 | old_row_col_address_unpack[1] : dstaddr_upper = new_row_col_address_unpack[1]; 89 | old_row_col_address_unpack[2] : dstaddr_upper = new_row_col_address_unpack[2]; 90 | old_row_col_address_unpack[3] : dstaddr_upper = new_row_col_address_unpack[3]; 91 | old_row_col_address_unpack[4] : dstaddr_upper = new_row_col_address_unpack[4]; 92 | old_row_col_address_unpack[5] : dstaddr_upper = new_row_col_address_unpack[5]; 93 | old_row_col_address_unpack[6] : dstaddr_upper = new_row_col_address_unpack[6]; 94 | old_row_col_address_unpack[7] : dstaddr_upper = new_row_col_address_unpack[7]; 95 | default : dstaddr_upper = umi_in_dstaddr[(IDSB+IDW-1):IDSB]; 96 | endcase 97 | end 98 | 99 | wire [AW-1:0] dstaddr_with_remap; 100 | generate 101 | if ((IDSB+IDW) < AW) begin : REMAP_ADDR_WITH_MSB 102 | assign dstaddr_with_remap = {umi_in_dstaddr[AW-1:IDSB+IDW], 103 | dstaddr_upper, 104 | umi_in_dstaddr[IDSB-1:0]}; 105 | end 106 | else begin : REMAP_ADDR_WO_MSB 107 | assign dstaddr_with_remap = {dstaddr_upper, umi_in_dstaddr[IDSB-1:0]}; 108 | end 109 | endgenerate 110 | 111 | // Address offsetting 112 | wire dstaddr_offset_en; 113 | wire [AW-1:0] dstaddr_with_offset; 114 | 115 | assign dstaddr_offset_en = (umi_in_dstaddr >= set_dstaddress_low) & 116 | (umi_in_dstaddr <= set_dstaddress_high); 117 | assign dstaddr_with_offset = umi_in_dstaddr + set_dstaddress_offset; 118 | 119 | assign umi_out_valid = umi_in_valid; 120 | assign umi_out_cmd = umi_in_cmd; 121 | assign umi_out_dstaddr = (umi_in_dstaddr[(IDSB+IDW-1):IDSB] == chipid) ? 122 | umi_in_dstaddr : 123 | (dstaddr_offset_en ? 124 | dstaddr_with_offset : 125 | dstaddr_with_remap); 126 | assign umi_out_srcaddr = umi_in_srcaddr; 127 | assign umi_out_data = umi_in_data; 128 | assign umi_in_ready = umi_out_ready; 129 | 130 | endmodule 131 | -------------------------------------------------------------------------------- /umi/utils/testbench/config.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2022 Zero ASIC Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * ---- 17 | * 18 | * Documentation: 19 | * - Simulator global configurations 20 | * 21 | ******************************************************************************/ 22 | 23 | #pragma once 24 | 25 | #define CLK_PREIOD_PS (10000) 26 | #define CLK_HALF_PERIOD_PS (CLK_PREIOD_PS / 2) 27 | 28 | #define UART_BAUD (115200) 29 | 30 | #define RAM_BASE (0x00000000) 31 | #define RAM_SIZE (1024 * 1024 * 1024) 32 | 33 | #define RAM_LOAD_OFFSET (0x00000000) 34 | -------------------------------------------------------------------------------- /umi/utils/testbench/config.vlt: -------------------------------------------------------------------------------- 1 | `verilator_config 2 | //lint_off -file "*umi/umi/rtl/umi_mem_agent*" 3 | lint_off -rule WIDTHEXPAND 4 | //lint_off -file "*lambdalib/ramlib/*" 5 | //lint_off -file "*lambdalib/stdlib/*" 6 | lint_off -file "*verilog-axi/rtl/*" 7 | //lint_off -rule LATCH 8 | //lint_off -rule UNOPTFLAT 9 | //lint_off -rule SELRANGE 10 | lint_off -rule IMPLICIT 11 | lint_off -rule DECLFILENAME 12 | lint_off -rule PINCONNECTEMPTY 13 | lint_off -rule UNUSEDPARAM 14 | lint_off -rule UNUSEDSIGNAL 15 | lint_off -rule UNUSEDGENVAR 16 | lint_off -rule UNDRIVEN 17 | lint_off -rule BLKSEQ -file "*switchboard/switchboard/verilog/*" 18 | lint_off -rule GENUNNAMED 19 | lint_off -rule TIMESCALEMOD 20 | // To be fixed: 21 | //lint_off -rule SYNCASYNCNET 22 | //lint_off -rule WIDTHTRUNC 23 | -------------------------------------------------------------------------------- /umi/utils/testbench/tb_umi_data_aggregator.v: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2023 Zero ASIC Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * ---- 17 | * 18 | * Documentation: 19 | * - UMI data aggeregator testbench 20 | * 21 | ******************************************************************************/ 22 | 23 | 24 | `timescale 1ns / 1ps 25 | `default_nettype wire 26 | 27 | module tb_umi_data_aggregator #( 28 | parameter TARGET = "DEFAULT", // pass through variable for hard macro 29 | parameter TIMEOUT = 5000, // timeout value (cycles) 30 | parameter PERIOD_CLK = 10 // clock period 31 | ) 32 | (); 33 | 34 | // Local parameters 35 | localparam STIMDEPTH = 1024; 36 | localparam TCW = 8; 37 | localparam CW = 32; // UMI width 38 | localparam AW = 64; // UMI width 39 | localparam DW = 512; 40 | 41 | // Clock 42 | reg clk; 43 | 44 | always 45 | #(PERIOD_CLK/2) clk = ~clk; 46 | 47 | // SIM Ctrl signals 48 | reg nreset; 49 | reg [128*8-1:0] memhfile; 50 | reg load; 51 | reg go; 52 | integer r; 53 | 54 | // Reset initialization 55 | initial begin 56 | #(1) 57 | nreset = 1'b0; 58 | clk = 1'b0; 59 | load = 1'b0; 60 | go = 1'b0; 61 | #(PERIOD_CLK * 10) 62 | nreset = 1'b1; 63 | #(PERIOD_CLK * 10) 64 | go = 1'b1; 65 | end // initial begin 66 | 67 | // control block 68 | initial begin 69 | r = $value$plusargs("MEMHFILE=%s", memhfile); 70 | $readmemh(memhfile, umi_stimulus.ram); 71 | $timeformat(-9, 0, " ns", 20); 72 | $dumpfile("waveform.vcd"); 73 | $dumpvars(); 74 | #(TIMEOUT) 75 | $finish; 76 | end 77 | 78 | // DUT signals 79 | wire umi_stim2dut_valid; 80 | wire [CW-1:0] umi_stim2dut_cmd; 81 | wire [AW-1:0] umi_stim2dut_dstaddr; 82 | wire [AW-1:0] umi_stim2dut_srcaddr; 83 | wire [DW-1:0] umi_stim2dut_data; 84 | wire umi_stim2dut_ready; 85 | 86 | wire umi_dut2check_valid; 87 | wire [CW-1:0] umi_dut2check_cmd; 88 | wire [AW-1:0] umi_dut2check_dstaddr; 89 | wire [AW-1:0] umi_dut2check_srcaddr; 90 | wire [DW-1:0] umi_dut2check_data; 91 | reg umi_dut2check_ready; 92 | 93 | always @(posedge clk) begin 94 | if(~nreset) 95 | umi_dut2check_ready <= 1'b0; 96 | else 97 | umi_dut2check_ready <= ~umi_dut2check_ready; 98 | end 99 | 100 | umi_data_aggregator #( 101 | .CW (CW), 102 | .AW (AW), 103 | .DW (DW) 104 | ) dut ( 105 | .clk (clk), 106 | .nreset (nreset), 107 | 108 | .umi_in_valid (umi_stim2dut_valid), 109 | .umi_in_cmd (umi_stim2dut_cmd), 110 | .umi_in_dstaddr (umi_stim2dut_dstaddr), 111 | .umi_in_srcaddr (umi_stim2dut_srcaddr), 112 | .umi_in_data (umi_stim2dut_data), 113 | .umi_in_ready (umi_stim2dut_ready), 114 | 115 | .umi_out_valid (umi_dut2check_valid), 116 | .umi_out_cmd (umi_dut2check_cmd), 117 | .umi_out_dstaddr (umi_dut2check_dstaddr), 118 | .umi_out_srcaddr (umi_dut2check_srcaddr), 119 | .umi_out_data (umi_dut2check_data), 120 | .umi_out_ready (umi_dut2check_ready) 121 | ); 122 | 123 | umi_stimulus #( 124 | .DEPTH (STIMDEPTH), 125 | .TARGET (TARGET), 126 | .CW (CW), 127 | .AW (AW), 128 | .DW (DW), 129 | .TCW (TCW) 130 | ) umi_stimulus ( 131 | // Inputs 132 | .nreset (nreset), 133 | .load (load), 134 | .go (go), 135 | .ext_clk (clk), 136 | .ext_valid (1'b0), 137 | .ext_packet ({(DW+AW+AW+CW+TCW){1'b0}}), 138 | .dut_clk (clk), 139 | .dut_ready (umi_stim2dut_ready), 140 | 141 | // Outputs 142 | .stim_valid (umi_stim2dut_valid), 143 | .stim_cmd (umi_stim2dut_cmd[CW-1:0]), 144 | .stim_dstaddr (umi_stim2dut_dstaddr[AW-1:0]), 145 | .stim_srcaddr (umi_stim2dut_srcaddr[AW-1:0]), 146 | .stim_data (umi_stim2dut_data[DW-1:0]), 147 | .stim_done (umi_stim2dut_done) 148 | ); 149 | 150 | endmodule 151 | -------------------------------------------------------------------------------- /umi/utils/testbench/test_tl2umi_np.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from siliconcompiler import Chip 4 | from siliconcompiler.flows import dvflow 5 | from siliconcompiler.package import path as sc_path 6 | from umi import sumi 7 | 8 | 9 | def build(): 10 | chip = Chip('tb_tl2umi_np') 11 | chip.use(sumi) 12 | chip.use(dvflow, tool='icarus') 13 | 14 | chip.set('option', 'flow', 'dvflow') 15 | 16 | chip.input('utils/testbench/tb_tl2umi_np.v', package='umi') 17 | 18 | memfile = f"{sc_path(chip, 'umi')}/utils/testbench/buffer.memh" 19 | 20 | chip.add('tool', 'execute', 'task', 'exec_input', 'option', f'+MEMHFILE={memfile}') 21 | 22 | chip.run() 23 | 24 | 25 | if __name__ == "__main__": 26 | build() 27 | -------------------------------------------------------------------------------- /umi/utils/testbench/test_umi2apb.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2023 Zero ASIC 4 | # This code is licensed under Apache License 2.0 (see LICENSE for details) 5 | 6 | import random 7 | import numpy as np 8 | from switchboard import SbDut, UmiTxRx 9 | from umi import sumi 10 | 11 | 12 | def main(): 13 | 14 | extra_args = { 15 | '--vldmode': dict(type=int, default=1, help='Valid mode'), 16 | '--rdymode': dict(type=int, default=1, help='Ready mode'), 17 | '-n': dict(type=int, default=10, help='Number of transactions' 18 | 'to send during the test.') 19 | } 20 | 21 | dut = SbDut('testbench', cmdline=True, extra_args=extra_args, trace=False, default_main=True) 22 | 23 | # Set up inputs 24 | dut.input('utils/testbench/testbench_umi2apb.sv', package='umi') 25 | 26 | dut.use(sumi) 27 | 28 | # Verilator configuration 29 | dut.set('tool', 'verilator', 'task', 'compile', 'file', 'config', 'utils/testbench/config.vlt', 30 | package='umi') 31 | 32 | dut.build() 33 | 34 | # launch the simulation 35 | dut.simulate( 36 | plusargs=[ 37 | ('valid_mode', dut.args.vldmode), 38 | ('ready_mode', dut.args.rdymode) 39 | ] 40 | ) 41 | 42 | # instantiate TX and RX queues. note that these can be instantiated without 43 | # specifying a URI, in which case the URI can be specified later via the 44 | # "init" method 45 | 46 | host = UmiTxRx("host2dut_0.q", "dut2host_0.q", fresh=True) 47 | 48 | print("### Starting test ###") 49 | 50 | # regif accesses are all 32b wide and aligned 51 | for _ in range(dut.args.n): 52 | addr = np.random.randint(0, 512) * 4 53 | # length should not cross the DW boundary - umi_mem_agent limitation 54 | data = np.uint32(random.randrange(2**32-1)) 55 | 56 | print(f"umi writing 0x{data:08x} to addr 0x{addr:08x}") 57 | host.write(addr, data) 58 | 59 | print(f"umi read from addr 0x{addr:08x}") 60 | val = host.read(addr, np.uint32) 61 | if not (val == data): 62 | print(f"ERROR umi read from addr 0x{addr:08x} expected {data} actual {val}") 63 | assert (val == data) 64 | 65 | print("### TEST PASS ###") 66 | 67 | 68 | if __name__ == '__main__': 69 | main() 70 | -------------------------------------------------------------------------------- /umi/utils/testbench/test_umi2axilite.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2023 Zero ASIC 4 | # This code is licensed under Apache License 2.0 (see LICENSE for details) 5 | 6 | import random 7 | import numpy as np 8 | from switchboard import SbDut, UmiTxRx 9 | from umi import sumi 10 | 11 | 12 | def main(): 13 | 14 | extra_args = { 15 | '--vldmode': dict(type=int, default=1, help='Valid mode'), 16 | '--rdymode': dict(type=int, default=1, help='Ready mode'), 17 | } 18 | 19 | dut = SbDut('testbench', cmdline=True, extra_args=extra_args, 20 | trace=False, default_main=True) 21 | 22 | # Set up inputs 23 | dut.input('utils/testbench/testbench_umi2axilite.sv', package='umi') 24 | 25 | dut.use(sumi) 26 | 27 | # Verilator configuration 28 | dut.set('tool', 'verilator', 'task', 'compile', 'file', 'config', 29 | 'utils/testbench/config.vlt', 30 | package='umi') 31 | 32 | # Build simulator 33 | dut.build() 34 | 35 | # launch the simulation 36 | dut.simulate(plusargs=[('valid_mode', dut.args.vldmode), 37 | ('ready_mode', dut.args.rdymode)]) 38 | 39 | # instantiate TX and RX queues. note that these can be instantiated without 40 | # specifying a URI, in which case the URI can be specified later via the 41 | # "init" method 42 | 43 | host = UmiTxRx("host2dut_0.q", "dut2host_0.q", fresh=True) 44 | 45 | print("### Statring test ###") 46 | 47 | for count in range(1000): 48 | # length should not cross the DW boundary - umi_mem_agent limitation 49 | length = np.random.randint(0, 255) 50 | dst_addr = 32*random.randrange(2**(10-5)-1) # sb limitation - should align to bus width 51 | src_addr = 32*random.randrange(2**(10-5)-1) 52 | data8 = np.random.randint(0, 255, size=length, dtype=np.uint8) 53 | print(f"[{count}] umi writing {length} bytes to addr 0x{dst_addr:08x}") 54 | host.write(dst_addr, data8, srcaddr=src_addr, max_bytes=8) 55 | print(f"[{count}] umi read from addr 0x{dst_addr:08x}") 56 | val8 = host.read(dst_addr, length, np.uint8, srcaddr=src_addr, max_bytes=8) 57 | if ~((val8 == data8).all()): 58 | print(f"ERROR umi read from addr 0x{dst_addr:08x}") 59 | print(f"Expected: {data8}") 60 | print(f"Actual: {val8}") 61 | assert (val8 == data8).all() 62 | 63 | print("### TEST PASS ###") 64 | 65 | 66 | if __name__ == '__main__': 67 | main() 68 | -------------------------------------------------------------------------------- /umi/utils/testbench/test_umi2tl_np.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2023 Zero ASIC 4 | 5 | import random 6 | import numpy as np 7 | from pathlib import Path 8 | from switchboard import SbDut, UmiTxRx 9 | from siliconcompiler.package import path as sc_path 10 | from umi import sumi 11 | 12 | 13 | def main(): 14 | 15 | extra_args = { 16 | '--vldmode': dict(type=int, default=1, help='Valid mode'), 17 | '-n': dict(type=int, default=10, help='Number of transactions' 18 | 'to send during the test.') 19 | } 20 | 21 | dut = SbDut('testbench', cmdline=True, extra_args=extra_args, 22 | trace=False, trace_type='fst', default_main=False) 23 | 24 | # Set up inputs 25 | dut.input('utils/testbench/testbench_umi2tl_np.v', package='umi') 26 | dut.input('utils/testbench/testbench_umi2tl_np.cc', package='umi') 27 | dut.input('utils/testbench/tlmemsim.cpp', package='umi') 28 | 29 | dut.use(sumi) 30 | 31 | # Verilator configuration 32 | dut.add('tool', 'verilator', 'task', 'compile', 'option', '--coverage') 33 | header_files_dir = Path(sc_path(dut, 'umi')) / 'utils' / 'testbench' 34 | dut.set('tool', 'verilator', 'task', 'compile', 'var', 'cflags', f'-I{header_files_dir}') 35 | dut.set('tool', 'verilator', 'task', 'compile', 'file', 'config', 'utils/testbench/config.vlt', package='umi') 36 | 37 | # Build simulator 38 | dut.build() 39 | 40 | # launch the simulation 41 | dut.simulate(plusargs=[('valid_mode', dut.args.vldmode)]) 42 | 43 | # instantiate TX and RX queues. note that these can be instantiated without 44 | # specifying a URI, in which case the URI can be specified later via the 45 | # "init" method 46 | 47 | umi = UmiTxRx("client2rtl_0.q", "rtl2client_0.q", fresh=True) 48 | 49 | print("### Starting random test ###") 50 | 51 | n_sent = 0 52 | 53 | while (n_sent < dut.args.n): 54 | print(f"Transaction {n_sent}:") 55 | addr = random.randrange(511) 56 | length = random.choice([1, 2, 4, 8]) 57 | 58 | # FIXME: Align address. Limitation of umi2tl converter. Will be fixed in the next release 59 | addr = addr & (0xFFFFFFF8 | (8-length)) 60 | 61 | data8 = np.random.randint(0, 255, size=length, dtype=np.uint8) 62 | print(f"umi writing {length} bytes:: data: {data8} to addr: 0x{addr:08x}") 63 | umi.write(addr, data8, srcaddr=0x0000110000000000) 64 | print(f"umi reading {length} bytes:: from addr 0x{addr:08x}") 65 | val8 = umi.read(addr, length, np.uint8, srcaddr=0x0000110000000000) 66 | print(f"umi Read: {val8}") 67 | if not (val8 == data8).all(): 68 | print(f"ERROR core read from addr 0x{addr:08x} expected {data8} actual {val8}") 69 | assert (val8 == data8).all() 70 | n_sent = n_sent + 1 71 | 72 | 73 | if __name__ == '__main__': 74 | main() 75 | -------------------------------------------------------------------------------- /umi/utils/testbench/test_umi_address_remap.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2023 Zero ASIC 4 | 5 | import random 6 | from switchboard import SbDut, UmiTxRx, random_umi_packet 7 | from umi import sumi 8 | 9 | 10 | def main(): 11 | 12 | extra_args = { 13 | '--vldmode': dict(type=int, default=1, help='Valid mode'), 14 | '--rdymode': dict(type=int, default=1, help='Ready mode'), 15 | '-n': dict(type=int, default=10, help='Number of transactions' 16 | 'to send during the test.') 17 | } 18 | 19 | dut = SbDut('testbench', cmdline=True, extra_args=extra_args, 20 | trace=False, trace_type='fst', default_main=True) 21 | 22 | # Set up inputs 23 | dut.input('utils/testbench/testbench_umi_address_remap.v', package='umi') 24 | 25 | dut.use(sumi) 26 | 27 | # Verilator configuration 28 | dut.set('tool', 'verilator', 'task', 'compile', 29 | 'file', 'config', 'utils/testbench/config.vlt', package='umi') 30 | 31 | # Build simulator 32 | dut.build() 33 | 34 | # launch the simulation 35 | dut.simulate(plusargs=[('valid_mode', dut.args.vldmode), 36 | ('ready_mode', dut.args.rdymode)]) 37 | 38 | # instantiate TX and RX queues. note that these can be instantiated without 39 | # specifying a URI, in which case the URI can be specified later via the 40 | # "init" method 41 | 42 | umi = UmiTxRx("client2rtl_0.q", "rtl2client_0.q", fresh=True) 43 | 44 | print("### Starting random test ###") 45 | 46 | n_sent = 0 47 | n_recv = 0 48 | txq = [] 49 | 50 | while (n_sent < dut.args.n) or (n_recv < dut.args.n): 51 | addr = random.randrange(0x0000_0000_0000_0000, 0x0000_07FF_FFFF_FFFF) 52 | addr = addr & 0xFFFF_FF00_0000_FFF0 # Allow different devices but reduce address space per device 53 | 54 | txp = random_umi_packet(dstaddr=addr, srcaddr=0x0000110000000000) 55 | if n_sent < dut.args.n: 56 | if umi.send(txp, blocking=False): 57 | print(f"Transaction sent: {n_sent}") 58 | print(str(txp)) 59 | txq.append(txp) 60 | # Offset 61 | if ((addr >= 0x0000_0600_0000_0080) and 62 | (addr <= 0x0000_06FF_FFFF_FFFF)): 63 | addr = addr - 0x0000_0000_0000_0080 64 | txq[-1].dstaddr = addr 65 | # Remap 66 | elif ((addr & 0xFFFF_FF00_0000_0000) != 0x0000_0400_0000_0000): 67 | addr = addr ^ 0x00FF_FF00_0000_0000 68 | txq[-1].dstaddr = addr 69 | n_sent += 1 70 | 71 | if n_recv < dut.args.n: 72 | rxp = umi.recv(blocking=False) 73 | if rxp is not None: 74 | print(f"Transaction received: {n_recv}") 75 | print(str(rxp)) 76 | if rxp != txq[0]: 77 | raise Exception(f'Mismatch! {n_recv}') 78 | else: 79 | txq.pop(0) 80 | n_recv += 1 81 | 82 | 83 | if __name__ == '__main__': 84 | main() 85 | -------------------------------------------------------------------------------- /umi/utils/testbench/test_umi_packet_merge_greedy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2023 Zero ASIC 4 | 5 | from switchboard import SbDut, UmiTxRx, random_umi_packet 6 | from umi import sumi 7 | 8 | 9 | def main(): 10 | 11 | extra_args = { 12 | '--vldmode': dict(type=int, default=1, help='Valid mode'), 13 | '-n': dict(type=int, default=10, help='Number of transactions' 14 | 'to send during the test.') 15 | } 16 | 17 | dut = SbDut('testbench', cmdline=True, extra_args=extra_args, 18 | trace=False, trace_type='fst', default_main=False) 19 | 20 | # Set up inputs 21 | dut.input('utils/testbench/testbench_umi_packet_merge_greedy.v', package='umi') 22 | dut.input('utils/testbench/testbench_umi_packet_merge_greedy.cc', package='umi') 23 | 24 | dut.use(sumi) 25 | 26 | # Verilator configuration 27 | dut.set('tool', 'verilator', 'task', 'compile', 28 | 'file', 'config', 'utils/testbench/config.vlt', package='umi') 29 | dut.add('tool', 'verilator', 'task', 'compile', 'option', '--coverage') 30 | 31 | # Build simulator 32 | dut.build() 33 | 34 | # launch the simulation 35 | ret_val = dut.simulate(plusargs=[('valid_mode', dut.args.vldmode)]) 36 | 37 | # instantiate TX and RX queues. note that these can be instantiated without 38 | # specifying a URI, in which case the URI can be specified later via the 39 | # "init" method 40 | 41 | umi = UmiTxRx("client2rtl_0.q", "rtl2client_0.q", fresh=True) 42 | 43 | print("### Starting random test ###") 44 | 45 | n_sent = 0 46 | 47 | while (n_sent < dut.args.n): 48 | txp = random_umi_packet() 49 | if umi.send(txp, blocking=False): 50 | print('* TX *') 51 | print(str(txp)) 52 | n_sent += 1 53 | 54 | ret_val.wait() 55 | 56 | 57 | if __name__ == '__main__': 58 | main() 59 | -------------------------------------------------------------------------------- /umi/utils/testbench/testbench_umi2tl_np.cc: -------------------------------------------------------------------------------- 1 | // For Ctrl-C handling 2 | #include 3 | 4 | // For std::unique_ptr 5 | #include 6 | 7 | // Include common routines 8 | #include 9 | 10 | // Include model header, generated from Verilating "top.v" 11 | #include "Vtestbench.h" 12 | 13 | #include "config.h" 14 | #include "tlmemsim.h" 15 | 16 | // Legacy function required only so linking works on Cygwin and MSVC++ 17 | double sc_time_stamp() { 18 | return 0; 19 | } 20 | 21 | // ref: https://stackoverflow.com/a/4217052 22 | static volatile int got_sigint = 0; 23 | 24 | void sigint_handler(int unused) { 25 | got_sigint = 1; 26 | } 27 | 28 | int main(int argc, char** argv, char** env) { 29 | // Prevent unused variable warnings 30 | if (false && argc && argv && env) {} 31 | 32 | // Using unique_ptr is similar to 33 | // "VerilatedContext* contextp = new VerilatedContext" then deleting at end. 34 | const std::unique_ptr contextp{new VerilatedContext}; 35 | // Do not instead make Vtop as a file-scope static variable, as the 36 | // "C++ static initialization order fiasco" may cause a crash 37 | 38 | // Verilator must compute traced signals 39 | contextp->traceEverOn(true); 40 | 41 | // Pass arguments so Verilated code can see them, e.g. $value$plusargs 42 | // This needs to be called before you create any model 43 | contextp->commandArgs(argc, argv); 44 | 45 | // Construct the Verilated model, from Vtop.h generated from Verilating "top.v". 46 | // Using unique_ptr is similar to "Vtop* top = new Vtop" then deleting at end. 47 | // "TOP" will be the hierarchical name of the module. 48 | const std::unique_ptr top{new Vtestbench{contextp.get(), "TOP"}}; 49 | TLMemsim *ram{new TLMemsim(RAM_BASE, RAM_SIZE)}; 50 | 51 | ram->reset(); 52 | 53 | // Set Vtestbench's input signals 54 | top->clk = 0; 55 | top->eval(); 56 | 57 | // Set up Ctrl-C handler 58 | signal(SIGINT, sigint_handler); 59 | 60 | // Main loop 61 | while (!(contextp->gotFinish() || got_sigint)) { 62 | // Historical note, before Verilator 4.200 Verilated::gotFinish() 63 | // was used above in place of contextp->gotFinish(). 64 | // Most of the contextp-> calls can use Verilated:: calls instead; 65 | // the Verilated:: versions just assume there's a single context 66 | // being used (per thread). It's faster and clearer to use the 67 | // newer contextp-> versions. 68 | 69 | // Historical note, before Verilator 4.200 a sc_time_stamp() 70 | // function was required instead of using timeInc. Once timeInc() 71 | // is called (with non-zero), the Verilated libraries assume the 72 | // new API, and sc_time_stamp() will no longer work. 73 | 74 | uint8_t tl_a_ready = top->tl_a_ready; 75 | uint8_t tl_d_valid = top->tl_d_valid; 76 | uint8_t tl_d_opcode = top->tl_d_opcode; 77 | uint8_t tl_d_param = top->tl_d_param; 78 | uint8_t tl_d_size = top->tl_d_size; 79 | uint8_t tl_d_source = top->tl_d_source; 80 | uint8_t tl_d_sink = top->tl_d_sink; 81 | uint8_t tl_d_denied = top->tl_d_denied; 82 | uint8_t tl_d_corrupt = top->tl_d_corrupt; 83 | uint64_t tl_d_data = top->tl_d_data; 84 | 85 | ram->apply( 86 | tl_a_ready, 87 | top->tl_a_valid, 88 | top->tl_a_opcode, 89 | top->tl_a_param, 90 | top->tl_a_size, 91 | top->tl_a_source, 92 | top->tl_a_address, 93 | top->tl_a_mask, 94 | top->tl_a_data, 95 | top->tl_a_corrupt, 96 | top->tl_d_ready, 97 | tl_d_valid, 98 | tl_d_opcode, 99 | tl_d_param, 100 | tl_d_size, 101 | tl_d_source, 102 | tl_d_sink, 103 | tl_d_denied, 104 | tl_d_data, 105 | tl_d_corrupt 106 | ); 107 | 108 | // Toggle a fast (time/2 period) clock 109 | top->clk = 1; 110 | 111 | // Evaluate model 112 | // (If you have multiple models being simulated in the same 113 | // timestep then instead of eval(), call eval_step() on each, then 114 | // eval_end_step() on each. See the manual.) 115 | top->eval(); 116 | 117 | contextp->timeInc(1); // 1 timeprecision period passes... 118 | 119 | // Apply changed input signals after clock edge 120 | top->tl_a_ready = tl_a_ready; 121 | top->tl_d_valid = tl_d_valid; 122 | top->tl_d_opcode = tl_d_opcode; 123 | top->tl_d_param = tl_d_param; 124 | top->tl_d_size = tl_d_size; 125 | top->tl_d_source = tl_d_source; 126 | top->tl_d_sink = tl_d_sink; 127 | top->tl_d_denied = tl_d_denied; 128 | top->tl_d_corrupt = tl_d_corrupt; 129 | top->tl_d_data = tl_d_data; 130 | 131 | top->eval(); 132 | 133 | contextp->timeInc(9); // 1 timeprecision period passes... 134 | 135 | top->clk = 0; 136 | top->eval(); 137 | contextp->timeInc(1); // 1 timeprecision period passes... 138 | 139 | // If you have C++ model logic that changes after the negative edge it goes here 140 | top->eval(); 141 | contextp->timeInc(9); // 1 timeprecision period passes... 142 | } 143 | 144 | if (VM_COVERAGE) { 145 | //printf("\n\nYes, Coverage is here\n\n"); 146 | contextp->coveragep()->forcePerInstance(true); 147 | contextp->coveragep()->write("coverage.dat"); 148 | } 149 | 150 | // Final model cleanup 151 | top->final(); 152 | 153 | // Return good completion status 154 | // Don't use exit() or destructor won't get called 155 | return 0; 156 | } 157 | -------------------------------------------------------------------------------- /umi/utils/testbench/testbench_umi2tl_np.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | `default_nettype none 3 | 4 | `include "switchboard.vh" 5 | 6 | module testbench #( 7 | parameter ODW = 64, 8 | parameter TARGET = "DEFAULT", // pass through variable for hard macro 9 | parameter TIMEOUT = 5000 // timeout value (cycles) 10 | ) 11 | ( 12 | input wire clk, 13 | 14 | // TileLink 15 | input wire tl_a_ready, 16 | output wire tl_a_valid, 17 | output wire [2:0] tl_a_opcode, 18 | output wire [2:0] tl_a_param, 19 | output wire [2:0] tl_a_size, 20 | output wire [3:0] tl_a_source, 21 | output wire [55:0] tl_a_address, 22 | output wire [7:0] tl_a_mask, 23 | output wire [ODW-1:0] tl_a_data, 24 | output wire tl_a_corrupt, 25 | 26 | output wire tl_d_ready, 27 | input wire tl_d_valid, 28 | input wire [2:0] tl_d_opcode, 29 | input wire [1:0] tl_d_param, 30 | input wire [2:0] tl_d_size, 31 | input wire [3:0] tl_d_source, 32 | input wire tl_d_sink, 33 | input wire tl_d_denied, 34 | input wire [ODW-1:0] tl_d_data, 35 | input wire tl_d_corrupt 36 | ); 37 | 38 | parameter integer PERIOD_CLK = 10; 39 | parameter integer TCW = 8; 40 | parameter integer IOW = 64; 41 | parameter integer NUMI = 2; 42 | 43 | // Local parameters 44 | localparam CW = 32; 45 | localparam AW = 64; 46 | localparam IDW = 128; 47 | 48 | // SIM Ctrl signals 49 | wire nreset; 50 | wire go; 51 | reg [15:0] nreset_vec = 16'h00; 52 | 53 | // Reset initialization 54 | always @(posedge clk) begin 55 | nreset_vec <= {nreset_vec[14:0], 1'b1}; 56 | end 57 | 58 | assign nreset = nreset_vec[14]; 59 | assign go = nreset_vec[15]; 60 | 61 | // DUT signals 62 | wire umi_rx2dut_valid; 63 | wire [CW-1:0] umi_rx2dut_cmd; 64 | wire [AW-1:0] umi_rx2dut_dstaddr; 65 | wire [AW-1:0] umi_rx2dut_srcaddr; 66 | wire [IDW-1:0] umi_rx2dut_data; 67 | wire umi_rx2dut_ready; 68 | 69 | wire umi_dut2tx_valid; 70 | wire [CW-1:0] umi_dut2tx_cmd; 71 | wire [AW-1:0] umi_dut2tx_dstaddr; 72 | wire [AW-1:0] umi_dut2tx_srcaddr; 73 | wire [IDW-1:0] umi_dut2tx_data; 74 | wire umi_dut2tx_ready; 75 | 76 | umi2tl_np #( 77 | .CW (CW), 78 | .AW (AW), 79 | .IDW (IDW), 80 | .ODW (ODW) 81 | ) dut ( 82 | .clk (clk), 83 | .nreset (nreset), 84 | 85 | .tl_a_ready (tl_a_ready), 86 | .tl_a_valid (tl_a_valid), 87 | .tl_a_opcode (tl_a_opcode), 88 | .tl_a_param (tl_a_param), 89 | .tl_a_size (tl_a_size), 90 | .tl_a_source (tl_a_source), 91 | .tl_a_address (tl_a_address), 92 | .tl_a_mask (tl_a_mask), 93 | .tl_a_data (tl_a_data), 94 | .tl_a_corrupt (tl_a_corrupt), 95 | 96 | .tl_d_ready (tl_d_ready), 97 | .tl_d_valid (tl_d_valid), 98 | .tl_d_opcode (tl_d_opcode), 99 | .tl_d_param (tl_d_param), 100 | .tl_d_size (tl_d_size), 101 | .tl_d_source (tl_d_source), 102 | .tl_d_sink (tl_d_sink), 103 | .tl_d_denied (tl_d_denied), 104 | .tl_d_data (tl_d_data), 105 | .tl_d_corrupt (tl_d_corrupt), 106 | 107 | .udev_req_valid (umi_rx2dut_valid), 108 | .udev_req_cmd (umi_rx2dut_cmd), 109 | .udev_req_dstaddr (umi_rx2dut_dstaddr), 110 | .udev_req_srcaddr (umi_rx2dut_srcaddr), 111 | .udev_req_data (umi_rx2dut_data), 112 | .udev_req_ready (umi_rx2dut_ready), 113 | 114 | .udev_resp_valid (umi_dut2tx_valid), 115 | .udev_resp_cmd (umi_dut2tx_cmd), 116 | .udev_resp_dstaddr (umi_dut2tx_dstaddr), 117 | .udev_resp_srcaddr (umi_dut2tx_srcaddr), 118 | .udev_resp_data (umi_dut2tx_data), 119 | .udev_resp_ready (umi_dut2tx_ready) 120 | ); 121 | 122 | queue_to_umi_sim #( 123 | .VALID_MODE_DEFAULT(2) 124 | ) umi_rx_i ( 125 | .clk (clk), 126 | 127 | .valid (umi_rx2dut_valid), 128 | .cmd (umi_rx2dut_cmd[CW-1:0]), 129 | .dstaddr (umi_rx2dut_dstaddr[AW-1:0]), 130 | .srcaddr (umi_rx2dut_srcaddr[AW-1:0]), 131 | .data (umi_rx2dut_data[IDW-1:0]), 132 | .ready (umi_rx2dut_ready) 133 | ); 134 | 135 | umi_to_queue_sim #( 136 | .READY_MODE_DEFAULT(2) 137 | ) umi_tx_i ( 138 | .clk (clk), 139 | 140 | .valid (umi_dut2tx_valid), 141 | .cmd (umi_dut2tx_cmd), 142 | .dstaddr (umi_dut2tx_dstaddr), 143 | .srcaddr (umi_dut2tx_srcaddr), 144 | .data ({128'd0, umi_dut2tx_data[127:0]}), 145 | .ready (umi_dut2tx_ready) 146 | ); 147 | 148 | // Initialize UMI 149 | integer valid_mode, ready_mode; 150 | 151 | initial begin 152 | if (!$value$plusargs("valid_mode=%d", valid_mode)) begin 153 | valid_mode = 2; // default if not provided as a plusarg 154 | end 155 | 156 | if (!$value$plusargs("ready_mode=%d", ready_mode)) begin 157 | ready_mode = 2; // default if not provided as a plusarg 158 | end 159 | 160 | umi_rx_i.init("client2rtl_0.q"); 161 | umi_rx_i.set_valid_mode(valid_mode); 162 | 163 | umi_tx_i.init("rtl2client_0.q"); 164 | umi_tx_i.set_ready_mode(ready_mode); 165 | end 166 | 167 | // control block 168 | `SB_SETUP_PROBES 169 | 170 | // auto-stop 171 | auto_stop_sim auto_stop_sim_i (.clk(clk)); 172 | 173 | endmodule 174 | 175 | `default_nettype wire 176 | -------------------------------------------------------------------------------- /umi/utils/testbench/testbench_umi_address_remap.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | `default_nettype none 3 | 4 | `include "switchboard.vh" 5 | 6 | module testbench #( 7 | parameter TARGET = "DEFAULT", // pass through variable for hard macro 8 | parameter TIMEOUT = 5000 // timeout value (cycles) 9 | ) 10 | ( 11 | input clk 12 | ); 13 | 14 | parameter integer PERIOD_CLK = 10; 15 | parameter integer TCW = 8; 16 | parameter integer IOW = 64; 17 | parameter integer NUMI = 2; 18 | 19 | // Local parameters 20 | localparam CW = 32; // UMI width 21 | localparam AW = 64; // UMI width 22 | localparam DW = 256; 23 | localparam IDW = 16; 24 | localparam IDSB = 40; 25 | localparam NMAPS = 8; 26 | 27 | genvar i; 28 | wire [IDW*NMAPS-1:0] old_row_col_address; 29 | wire [IDW*NMAPS-1:0] new_row_col_address; 30 | 31 | generate 32 | for (i = 0; i < NMAPS; i = i + 1) begin 33 | assign old_row_col_address[(IDW*(i+1))-1 : (IDW*i)] = i; 34 | assign new_row_col_address[(IDW*(i+1))-1 : (IDW*i)] = ~i; 35 | end 36 | endgenerate 37 | 38 | // DUT signals 39 | wire umi_stim2dut_valid; 40 | wire [CW-1:0] umi_stim2dut_cmd; 41 | wire [AW-1:0] umi_stim2dut_dstaddr; 42 | wire [AW-1:0] umi_stim2dut_srcaddr; 43 | wire [DW-1:0] umi_stim2dut_data; 44 | wire umi_stim2dut_ready; 45 | 46 | wire umi_dut2check_valid; 47 | wire [CW-1:0] umi_dut2check_cmd; 48 | wire [AW-1:0] umi_dut2check_dstaddr; 49 | wire [AW-1:0] umi_dut2check_srcaddr; 50 | wire [DW-1:0] umi_dut2check_data; 51 | wire umi_dut2check_ready; 52 | 53 | umi_address_remap #( 54 | .CW (CW), 55 | .AW (AW), 56 | .DW (DW), 57 | .IDW (IDW), 58 | .IDSB (IDSB), 59 | .NMAPS (NMAPS) 60 | ) dut ( 61 | .chipid (16'h0004), 62 | 63 | .old_row_col_address (old_row_col_address), 64 | .new_row_col_address (new_row_col_address), 65 | 66 | .set_dstaddress_low (64'h0000_0600_0000_0080), 67 | .set_dstaddress_high (64'h0000_06FF_FFFF_FFFF), 68 | .set_dstaddress_offset (64'hFFFF_FFFF_FFFF_FF80), 69 | 70 | .umi_in_valid (umi_stim2dut_valid), 71 | .umi_in_cmd (umi_stim2dut_cmd), 72 | .umi_in_dstaddr (umi_stim2dut_dstaddr), 73 | .umi_in_srcaddr (umi_stim2dut_srcaddr), 74 | .umi_in_data (umi_stim2dut_data[DW-1:0]), 75 | .umi_in_ready (umi_stim2dut_ready), 76 | 77 | .umi_out_valid (umi_dut2check_valid), 78 | .umi_out_cmd (umi_dut2check_cmd), 79 | .umi_out_dstaddr (umi_dut2check_dstaddr), 80 | .umi_out_srcaddr (umi_dut2check_srcaddr), 81 | .umi_out_data (umi_dut2check_data), 82 | .umi_out_ready (umi_dut2check_ready) 83 | ); 84 | 85 | queue_to_umi_sim #( 86 | .VALID_MODE_DEFAULT(2) 87 | ) umi_rx_i ( 88 | .clk (clk), 89 | 90 | .valid (umi_stim2dut_valid), 91 | .cmd (umi_stim2dut_cmd[CW-1:0]), 92 | .dstaddr (umi_stim2dut_dstaddr[AW-1:0]), 93 | .srcaddr (umi_stim2dut_srcaddr[AW-1:0]), 94 | .data (umi_stim2dut_data), 95 | .ready (umi_stim2dut_ready) 96 | ); 97 | 98 | umi_to_queue_sim #( 99 | .READY_MODE_DEFAULT(2) 100 | ) umi_tx_i ( 101 | .clk (clk), 102 | 103 | .valid (umi_dut2check_valid), 104 | .cmd (umi_dut2check_cmd), 105 | .dstaddr (umi_dut2check_dstaddr), 106 | .srcaddr (umi_dut2check_srcaddr), 107 | .data (umi_dut2check_data), 108 | .ready (umi_dut2check_ready) 109 | ); 110 | 111 | // Initialize UMI 112 | integer valid_mode, ready_mode; 113 | 114 | initial begin 115 | if (!$value$plusargs("valid_mode=%d", valid_mode)) begin 116 | valid_mode = 2; // default if not provided as a plusarg 117 | end 118 | 119 | if (!$value$plusargs("ready_mode=%d", ready_mode)) begin 120 | ready_mode = 2; // default if not provided as a plusarg 121 | end 122 | 123 | umi_rx_i.init("client2rtl_0.q"); 124 | umi_rx_i.set_valid_mode(valid_mode); 125 | 126 | umi_tx_i.init("rtl2client_0.q"); 127 | umi_tx_i.set_ready_mode(ready_mode); 128 | end 129 | 130 | // control block 131 | `SB_SETUP_PROBES 132 | 133 | // auto-stop 134 | auto_stop_sim auto_stop_sim_i (.clk(clk)); 135 | 136 | endmodule 137 | 138 | `default_nettype wire 139 | -------------------------------------------------------------------------------- /umi/utils/testbench/testbench_umi_packet_merge_greedy.cc: -------------------------------------------------------------------------------- 1 | // For Ctrl-C handling 2 | #include 3 | 4 | // For std::unique_ptr 5 | #include 6 | 7 | // Include common routines 8 | #include 9 | 10 | // Include model header, generated from Verilating "top.v" 11 | #include "Vtestbench.h" 12 | 13 | // Legacy function required only so linking works on Cygwin and MSVC++ 14 | double sc_time_stamp() { 15 | return 0; 16 | } 17 | 18 | // ref: https://stackoverflow.com/a/4217052 19 | static volatile int got_sigint = 0; 20 | 21 | void sigint_handler(int unused) { 22 | got_sigint = 1; 23 | } 24 | 25 | int main(int argc, char** argv, char** env) { 26 | // Prevent unused variable warnings 27 | if (false && argc && argv && env) {} 28 | 29 | // Using unique_ptr is similar to 30 | // "VerilatedContext* contextp = new VerilatedContext" then deleting at end. 31 | const std::unique_ptr contextp{new VerilatedContext}; 32 | // Do not instead make Vtop as a file-scope static variable, as the 33 | // "C++ static initialization order fiasco" may cause a crash 34 | 35 | // Verilator must compute traced signals 36 | contextp->traceEverOn(true); 37 | 38 | // Pass arguments so Verilated code can see them, e.g. $value$plusargs 39 | // This needs to be called before you create any model 40 | contextp->commandArgs(argc, argv); 41 | 42 | // Construct the Verilated model, from Vtop.h generated from Verilating "top.v". 43 | // Using unique_ptr is similar to "Vtop* top = new Vtop" then deleting at end. 44 | // "TOP" will be the hierarchical name of the module. 45 | const std::unique_ptr top{new Vtestbench{contextp.get(), "TOP"}}; 46 | 47 | // Set Vtestbench's input signals 48 | top->clk = 0; 49 | top->eval(); 50 | 51 | // Set up Ctrl-C handler 52 | signal(SIGINT, sigint_handler); 53 | 54 | // Main loop 55 | while (!(contextp->gotFinish() || got_sigint)) { 56 | // Historical note, before Verilator 4.200 Verilated::gotFinish() 57 | // was used above in place of contextp->gotFinish(). 58 | // Most of the contextp-> calls can use Verilated:: calls instead; 59 | // the Verilated:: versions just assume there's a single context 60 | // being used (per thread). It's faster and clearer to use the 61 | // newer contextp-> versions. 62 | 63 | contextp->timeInc(1); // 1 timeprecision period passes... 64 | // Historical note, before Verilator 4.200 a sc_time_stamp() 65 | // function was required instead of using timeInc. Once timeInc() 66 | // is called (with non-zero), the Verilated libraries assume the 67 | // new API, and sc_time_stamp() will no longer work. 68 | 69 | // Toggle a fast (time/2 period) clock 70 | top->clk = !top->clk; 71 | 72 | // Evaluate model 73 | // (If you have multiple models being simulated in the same 74 | // timestep then instead of eval(), call eval_step() on each, then 75 | // eval_end_step() on each. See the manual.) 76 | top->eval(); 77 | } 78 | 79 | if (VM_COVERAGE) { 80 | //printf("\n\nYes, Coverage is here\n\n"); 81 | contextp->coveragep()->forcePerInstance(true); 82 | contextp->coveragep()->write("coverage.dat"); 83 | } 84 | 85 | // Final model cleanup 86 | top->final(); 87 | 88 | // Return good completion status 89 | // Don't use exit() or destructor won't get called 90 | return 0; 91 | } 92 | -------------------------------------------------------------------------------- /umi/utils/testbench/testbench_umi_packet_merge_greedy.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | `default_nettype none 3 | 4 | `include "switchboard.vh" 5 | 6 | module testbench #( 7 | parameter TARGET = "DEFAULT", // pass through variable for hard macro 8 | parameter TIMEOUT = 5000 // timeout value (cycles) 9 | ) 10 | ( 11 | input clk 12 | ); 13 | 14 | parameter integer PERIOD_CLK = 10; 15 | parameter integer TCW = 8; 16 | parameter integer IOW = 64; 17 | parameter integer NUMI = 2; 18 | 19 | // Local parameters 20 | localparam CW = 32; // UMI width 21 | localparam AW = 64; // UMI width 22 | localparam IDW = 128; 23 | localparam ODW = 512; 24 | 25 | // SIM Ctrl signals 26 | wire nreset; 27 | wire go; 28 | reg [15:0] nreset_vec = 16'h0000; 29 | 30 | // Reset initialization 31 | always @(posedge clk) begin 32 | nreset_vec <= {nreset_vec[14:0], 1'b1}; 33 | end 34 | 35 | assign nreset = nreset_vec[14]; 36 | assign go = nreset_vec[15]; 37 | 38 | // DUT signals 39 | wire umi_stim2dut_valid; 40 | wire [CW-1:0] umi_stim2dut_cmd; 41 | wire [AW-1:0] umi_stim2dut_dstaddr; 42 | wire [AW-1:0] umi_stim2dut_srcaddr; 43 | wire [IDW-1:0] umi_stim2dut_data; 44 | wire umi_stim2dut_ready; 45 | 46 | wire umi_dut2check_valid; 47 | wire [CW-1:0] umi_dut2check_cmd; 48 | wire [AW-1:0] umi_dut2check_dstaddr; 49 | wire [AW-1:0] umi_dut2check_srcaddr; 50 | wire [ODW-1:0] umi_dut2check_data; 51 | reg umi_dut2check_ready; 52 | 53 | always @(posedge clk or negedge nreset) begin 54 | if(~nreset) 55 | umi_dut2check_ready <= 1'b0; 56 | else 57 | umi_dut2check_ready <= ~umi_dut2check_ready; 58 | end 59 | 60 | umi_packet_merge_greedy #( 61 | .CW (CW), 62 | .AW (AW), 63 | .IDW (IDW), 64 | .ODW (ODW) 65 | ) dut ( 66 | .clk (clk), 67 | .nreset (nreset), 68 | 69 | .umi_in_valid (umi_stim2dut_valid), 70 | .umi_in_cmd (umi_stim2dut_cmd), 71 | .umi_in_dstaddr (umi_stim2dut_dstaddr), 72 | .umi_in_srcaddr (umi_stim2dut_srcaddr), 73 | .umi_in_data (umi_stim2dut_data), 74 | .umi_in_ready (umi_stim2dut_ready), 75 | 76 | .umi_out_valid (umi_dut2check_valid), 77 | .umi_out_cmd (umi_dut2check_cmd), 78 | .umi_out_dstaddr (umi_dut2check_dstaddr), 79 | .umi_out_srcaddr (umi_dut2check_srcaddr), 80 | .umi_out_data (umi_dut2check_data), 81 | .umi_out_ready (umi_dut2check_ready) 82 | ); 83 | 84 | queue_to_umi_sim #( 85 | .VALID_MODE_DEFAULT(2) 86 | ) umi_rx_i ( 87 | .clk (clk), 88 | 89 | .valid (umi_stim2dut_valid), 90 | .cmd (umi_stim2dut_cmd[CW-1:0]), 91 | .dstaddr (umi_stim2dut_dstaddr[AW-1:0]), 92 | .srcaddr (umi_stim2dut_srcaddr[AW-1:0]), 93 | .data (umi_stim2dut_data[IDW-1:0]), 94 | .ready (umi_stim2dut_ready) 95 | ); 96 | 97 | // Initialize UMI 98 | integer valid_mode, ready_mode; 99 | 100 | initial begin 101 | if (!$value$plusargs("valid_mode=%d", valid_mode)) begin 102 | valid_mode = 2; // default if not provided as a plusarg 103 | end 104 | 105 | umi_rx_i.init("client2rtl_0.q"); 106 | umi_rx_i.set_valid_mode(valid_mode); 107 | end 108 | 109 | // control block 110 | `SB_SETUP_PROBES 111 | 112 | // auto-stop 113 | auto_stop_sim #(.CYCLES(50000)) auto_stop_sim_i (.clk(clk)); 114 | 115 | endmodule 116 | 117 | `default_nettype wire 118 | -------------------------------------------------------------------------------- /umi/utils/testbench/tilelink.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2022 Zero ASIC Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | ******************************************************************************/ 17 | 18 | #pragma once 19 | 20 | typedef enum { 21 | // TL-UL 22 | OP_Get = 4, 23 | OP_PutFullData = 0, 24 | OP_PutPartialData = 1, 25 | // TL-UH 26 | OP_ArithmeticData = 2, 27 | OP_LogicalData = 3, 28 | OP_Intent = 5 29 | } TLOpcode_AB; 30 | 31 | typedef enum { 32 | // TL-UL 33 | OP_AccessAckData = 1, 34 | OP_AccessAck = 0, 35 | // TL-UH 36 | OP_HintAck = 2 37 | } TLOpcode_CD; 38 | 39 | typedef enum { 40 | PA_MIN = 0, 41 | PA_MAX = 1, 42 | PA_MINU = 2, 43 | PA_MAXU = 3, 44 | PA_ADD = 4 45 | } TLParam_Arithmetic; 46 | 47 | typedef enum { 48 | PL_XOR = 0, 49 | PL_OR = 1, 50 | PL_AND = 2, 51 | PL_SWAP = 3 52 | } TLParam_Logical; 53 | -------------------------------------------------------------------------------- /umi/utils/testbench/tlmemsim.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2023 Zero ASIC Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | ******************************************************************************/ 17 | 18 | #pragma once 19 | 20 | class TLMemsim { 21 | public: 22 | TLMemsim(uint64_t base, uint64_t size); 23 | ~TLMemsim(); 24 | void reset(); 25 | void apply(uint8_t &a_ready, uint8_t a_valid, uint8_t a_opcode, 26 | uint8_t a_param, uint8_t a_size, uint8_t a_source, 27 | uint32_t a_address, uint8_t a_mask, uint64_t a_data, 28 | uint8_t a_corrupt, uint8_t d_ready, uint8_t &d_valid, 29 | uint8_t &d_opcode, uint8_t &d_param, uint8_t &d_size, 30 | uint8_t &d_source, uint8_t &d_sink, uint8_t &d_denied, 31 | uint64_t &d_data, uint8_t &d_corrupt); 32 | void load(const char *fn, size_t offset); 33 | private: 34 | // Configurations 35 | uint64_t base; 36 | uint64_t size; 37 | uint64_t *mem; 38 | // Current processing request 39 | int req_beatcount; 40 | uint64_t req_addr; 41 | uint8_t req_opcode; 42 | uint8_t req_source; 43 | uint8_t req_size; 44 | uint8_t req_param; 45 | int req_firstbeat; 46 | int req_bubble; 47 | uint64_t get_bitmask(uint8_t mask); 48 | int get_beats(uint8_t size); 49 | uint64_t read(uint64_t addr); 50 | void write(uint64_t addr, uint64_t data, uint8_t mask); 51 | uint64_t rmwa(uint64_t addr, uint64_t data, uint8_t mask, uint8_t param); 52 | uint64_t rmwl(uint64_t addr, uint64_t data, uint8_t mask, uint8_t param); 53 | }; 54 | --------------------------------------------------------------------------------