Unverified Commit 62b9cfa4 by Sayak Kundu Committed by GitHub

Merge pull request #37 from TILOS-AI-Institute/flow_scripts

Flow scripts
parents 60e8c9d9 944bc1f7
......@@ -527,6 +527,7 @@ We currently use the physical synthesis tool **Cadence Genus iSpatial** to obtai
**August 20:** <span style="color:blue">Matching the area utilization</span>. We revisited the area utilization of Our Ariane133 and realized that it (51%) is lower than that of Google’s Ariane (68%). So that this would not devalue our study, we created a second variant, “**Our Ariane133-NanGate45_68**”, which matches the area utilization of Google’s Ariane. Results are as given below.
### **Circuit Training Baseline Result on “Our Ariane133-NanGate45**<span style="color:red">**_68**</span>**".**
<a id="Ariane133_68_CT"></a>
<table>
<thead>
......@@ -1777,7 +1778,7 @@ At some point during the past weeks, we realized that this would also be a poten
</tbody>
</table>
Ariane 68%:
**Ariane 68%:**
<p align="center">
<img width="300" src="./images/image8.png" alg="Ariane133_68_CT_CMP_Place">
<img width="300" src="./images/image2.png" alg="Ariane133_68_CT_CMP_Route">
......@@ -2475,7 +2476,6 @@ We shared the Ariane133-NG45-68% protobuf netlist and clustered netlist with Goo
</table>
<p align="center">
<table>
<thead>
<tr>
......@@ -2507,7 +2507,6 @@ We shared the Ariane133-NG45-68% protobuf netlist and clustered netlist with Goo
</tr>
</tbody>
</table>
</p>
<p align="center">
<img width="300" src="./images/image48.png" alg="ariane133_68_ct_google_place">
......@@ -2515,7 +2514,7 @@ We shared the Ariane133-NG45-68% protobuf netlist and clustered netlist with Goo
</p>
**October 8:**
**October 9:**
<a id="Question9"></a>
**<span style="color:blue">Question 9.</span>** Are CT results stable? If not, how much does the outcome vary?
......@@ -4033,7 +4032,7 @@ In the following table we report the Kendall rank correlation coefficient for pr
<a id="MemPoolGroup_NG45_68"></a>
**Circuit Training Baseline Result on “Our MemPool_Group-NanGate45_68”.**
**Circuit Training Baseline Result on “Our MemPool_Group-NanGate45_68”.**
We have trained CT to generate a macro placement for the [MemPool Group design](../../Flows/NanGate45/mempool_group/). For this experiment we use the NanGate45 enablement; the initial canvas size is generated by setting utilization to 68%. We use the default hyperparameters used for Ariane to train CT for bp_quad design. The number of hard macros in MemPool Group is 324, so we update [max_sequence_length](https://github.com/google-research/circuit_training/blob/6a76e327a70b5f0c9e3291b57c085688386da04e/circuit_training/learning/ppo_collect.py#L53) to 325 in [ppo_collect.py](https://github.com/google-research/circuit_training/blob/6a76e327a70b5f0c9e3291b57c085688386da04e/circuit_training/learning/ppo_collect.py#L53) and [sequence_length](https://github.com/google-research/circuit_training/blob/6a76e327a70b5f0c9e3291b57c085688386da04e/circuit_training/learning/train_ppo.py#L57) to 325 in [train_ppo.py](https://github.com/google-research/circuit_training/blob/6a76e327a70b5f0c9e3291b57c085688386da04e/circuit_training/learning/train_ppo.py#L57).
......@@ -4212,7 +4211,7 @@ We have trained CT to generate a macro placement for the [MemPool Group design](
</p>
## **Pinned (to bottom) question list:**
**<span style="color:blue">[Question 1](#Question1).</span>** How does having an initial set of placement locations (from physical synthesis) affect the (relative) quality of the CT result?
**<span style="color:blue">[Question 2](#Question2).</span>** How does utilization affect the (relative) performance of CT?
**<span style="color:blue">[Question 3](#Question3).</span>** Is a testcase such as Ariane-133 “probative”, or do we need better testcases?
......
# Copyright 2021 ETH Zurich and University of Bologna.
# Solderpad Hardware License, Version 0.51, see LICENSE for details.
# SPDX-License-Identifier: SHL-0.51
*.log
*.dasm
*.trace
*.project
bender
.bender/*
.dvt/*
*build*
*results*
results*
log/
plots*
obj_dir
# Hardware Dependencies
All hardware dependencies in this folder are git repositories themselves that are flattened into this repository. They are managed by [Bender](https://github.com/fabianschuiki/bender) instead of git submodules or subtrees. This allows us to have a flat repository where all changes are visible in a single repository. The downside is that changes to the dependencies need to be pulled/pushed to the upstream repository manually. The flow to do so is described here.
## Add new dependency
1. To add a new dependency, simply add it to the `Bender.yml` file and execute `bender update`. This will check the new dependencies and create a new `Bender.lock` entry. You can double check the lock file to make sure the correct commit will be checked out.
2. Execute a bender command, like `bender script vsim`, which will trigger Bender to actually check out the repository.
3. Remove the `.git` folder in the new dependency, which will flatten it into the main repository.
4. Add all the files from the submodule to git and create a commit. Make sure the main repository's `.gitignore` file is not excluding important files from the new dependency.
## Push changes to upstream
If you modify a dependency to implement some fixes or upgrades you want to contribute back to the upstream repository use the following flow. We use the `axi` dependency as an example.
1. Make sure the main repository is in a clean state and everything is checked in.
2. Delete the folder containing your dependency: `rm -rf deps/axi`
3. Check out the folder with Bender. This will restore the folder from the last point you synchronized it with the upstream repository. `make build`
4. Reset the changes in the dependency folder that you just introduced by checking out the last synchronization point. `git checkout deps/axi`
5. Now you restored the `.git` folder linked with the correct commit. However, the remote will be in the `.bender` folder. Add the upstream remote you want to push to. `cd deps/axi; git remote add upstream https://github.com/pulp-platform/axi`
6. Create/Checkout a branch and add the changes, push them to the upstream repository.
7. Remote the `.git` folder in the repo to reflatten the repository and add a commit updating the `Bender.lock` file to indicate the synchronization point.
## Pull changes from upstream
1. Make sure the main repository is in a clean state and everything is checked in.
2. Make sure your dependency has no changes compared to the last synchronization point that are not yet merged with the upstream repository.
3. Delete the folder containing your dependency: `rm -rf deps/axi`
4. Change the `Bender.yml`/`Bender.lock` to the version you want to upgrade to.
5. Pull the dependency through Bender. `make build`
6. Remove the dependency's `.git` folder.
7. Commit the changes to the dependency and the changes to the `Bender.*` files to the main repository.
cache_root_dir: /home/gitlabci/buildcache/axi
artifacts:
vsim-%:
inputs:
- Bender.yml # external dependencies
- include
- .gitlab-ci.yml # vsim version
- scripts/compile_vsim.sh
- src
- test
outputs:
- build/work-%
synopsys_dc:
inputs:
- Bender.yml
- include
- .gitlab-ci.yml # DC version
- scripts/synth.sh
- src
- test
outputs:
- build/synth.completed
axi_addr_test-%:
inputs:
- Bender.yml
- include
- scripts/run_vsim.sh
- src/axi_pkg.sv
- src/axi_intf.sv
- src/axi_test.sv
- test/tb_axi_addr_test.sv
outputs:
- build/axi_addr_test-%.tested
axi_atop_filter-%:
inputs:
- Bender.yml
- include
- scripts/run_vsim.sh
- src/axi_pkg.sv
- src/axi_intf.sv
- src/axi_test.sv
- src/axi_atop_filter.sv
- test/tb_axi_atop_filter.sv
outputs:
- build/axi_atop_filter-%.tested
axi_cdc-%:
inputs:
- Bender.yml
- include
- scripts/run_vsim.sh
- src/axi_pkg.sv
- src/axi_intf.sv
- src/axi_test.sv
- src/axi_cdc_dst.sv
- src/axi_cdc_src.sv
- src/axi_cdc.sv
- test/tb_axi_cdc.sv
outputs:
- build/axi_cdc-%.tested
axi_delayer-%:
inputs:
- Bender.yml
- include
- scripts/run_vsim.sh
- src/axi_pkg.sv
- src/axi_intf.sv
- src/axi_test.sv
- src/axi_delayer.sv
- test/tb_axi_delayer.sv
outputs:
- build/axi_delayer-%.tested
axi_dw_downsizer-%:
inputs:
- Bender.yml
- include
- scripts/run_vsim.sh
- src/axi_pkg.sv
- src/axi_intf.sv
- src/axi_test.sv
- src/axi_dw_downsizer.sv
- src/axi_dw_converter.sv
- test/tb_axi_dw_downsizer.sv
outputs:
- build/axi_dw_downsizer-%.tested
axi_dw_upsizer-%:
inputs:
- Bender.yml
- include
- scripts/run_vsim.sh
- src/axi_pkg.sv
- src/axi_intf.sv
- src/axi_test.sv
- src/axi_dw_upsizer.sv
- src/axi_dw_converter.sv
- test/tb_axi_dw_upsizer.sv
outputs:
- build/axi_dw_upsizer-%.tested
axi_isolate-%:
inputs:
- Bender.yml
- include
- scripts/run_vsim.sh
- src/axi_pkg.sv
- src/axi_intf.sv
- src/axi_test.sv
- src/axi_isolate.sv
- test/tb_axi_isolate.sv
outputs:
- build/axi_isolate-%.tested
axi_iw_converter-%:
inputs:
- Bender.yml
- include
- scripts/run_vsim.sh
- src/axi_pkg.sv
- src/axi_intf.sv
- src/axi_test.sv
- src/axi_id_prepend.sv
- src/axi_id_remap.sv
- src/axi_demux.sv
- src/axi_serializer.sv
- src/axi_mux.sv
- src/axi_id_serialize.sv
- src/axi_iw_converter.sv
- test/tb_axi_iw_converter.sv
outputs:
- build/axi_iw_converter-%.tested
axi_lite_regs-%:
inputs:
- Bender.yml
- include
- scripts/run_vsim.sh
- src/axi_pkg.sv
- src/axi_intf.sv
- src/axi_test.sv
- src/axi_lite_regs.sv
- test/tb_axi_lite_regs.sv
outputs:
- build/axi_lite_regs-%.tested
axi_lite_to_apb-%:
inputs:
- Bender.yml
- include
- scripts/run_vsim.sh
- src/axi_pkg.sv
- src/axi_intf.sv
- src/axi_test.sv
- src/axi_lite_to_apb.sv
- test/tb_axi_lite_to_apb.sv
outputs:
- build/axi_lite_to_apb-%.tested
axi_lite_to_axi-%:
inputs:
- Bender.yml
- include
- scripts/run_vsim.sh
- src/axi_pkg.sv
- src/axi_intf.sv
- src/axi_test.sv
- src/axi_lite_to_axi.sv
- test/tb_axi_lite_to_axi.sv
outputs:
- build/axi_lite_to_axi-%.tested
axi_lite_mailbox-%:
inputs:
- Bender.yml
- include
- scripts/run_vsim.sh
- src/axi_pkg.sv
- src/axi_intf.sv
- src/axi_test.sv
- src/axi_lite_mailbox.sv
- test/tb_axi_lite_mailbox.sv
outputs:
- build/axi_lite_mailbox-%.tested
axi_lite_xbar-%:
inputs:
- Bender.yml
- include
- scripts/run_vsim.sh
- src/axi_pkg.sv
- src/axi_intf.sv
- src/axi_test.sv
- src/axi_err_slv.sv
- src/axi_lite_demux.sv
- src/axi_lite_mux.sv
- src/axi_lite_to_axi.sv
- src/axi_lite_xbar.sv
- test/tb_axi_lite_xbar.sv
outputs:
- build/axi_lite_xbar-%.tested
axi_modify_address-%:
inputs:
- Bender.yml
- include
- scripts/run_vsim.sh
- src/axi_pkg.sv
- src/axi_intf.sv
- src/axi_test.sv
- src/axi_modify_address.sv
- test/tb_axi_modify_address.sv
outputs:
- build/axi_modify_address-%.tested
axi_serializer-%:
inputs:
- Bender.yml
- include
- scripts/run_vsim.sh
- src/axi_pkg.sv
- src/axi_intf.sv
- src/axi_test.sv
- src/axi_serializer.sv
- test/tb_axi_serializer.sv
outputs:
- build/axi_serializer-%.tested
axi_sim_mem-%:
inputs:
- Bender.yml
- include
- scripts/run_vsim.sh
- src/axi_pkg.sv
- src/axi_intf.sv
- src/axi_test.sv
- src/axi_sim_mem.sv
- test/tb_axi_sim_mem.sv
outputs:
- build/axi_sim_mem-%.tested
axi_to_axi_lite-%:
inputs:
- Bender.yml
- include
- scripts/run_vsim.sh
- src/axi_pkg.sv
- src/axi_intf.sv
- src/axi_test.sv
- src/axi_atop_filter.sv
- src/axi_burst_splitter.sv
- src/axi_to_axi_lite.sv
- test/tb_axi_to_axi_lite.sv
outputs:
- build/axi_to_axi_lite-%.tested
axi_xbar-%:
inputs:
- Bender.yml
- include
- scripts/run_vsim.sh
- src/axi_pkg.sv
- src/axi_intf.sv
- src/axi_test.sv
- src/axi_demux.sv
- src/axi_err_slv.sv
- src/axi_mux.sv
- src/axi_xbar.sv
- test/tb_axi_xbar.sv
outputs:
- build/axi_xbar-%.tested
name: Build and deploy documentation
on:
push:
branches-ignore:
- gh-pages # deployment target branch (this workflow should not exist on that branch anyway)
- v** # such branch names conflict with tags
tags:
- v**
pull_request:
branches-ignore:
- gh-pages # deployment target branch (this workflow should not exist on that branch anyway)
- v** # such branch names conflict with tags
jobs:
build-and-deploy:
if: github.repository == 'pulp-platform/axi' # do not run this job on forks (because deployment
runs-on: ubuntu-latest # will fail)
steps:
- name: Checkout
uses: actions/checkout@v2
with:
persist-credentials: false
- name: Cache cargo registry
uses: actions/cache@v1
with:
path: ~/.cargo/registry
key: ubuntu-latest-cargo-registry-${{ hashFiles('.github/workflows/doc.yml') }}
- name: Cache cargo index
uses: actions/cache@v1
with:
path: ~/.cargo/git
key: ubuntu-latest-cargo-index-${{ hashFiles('.github/workflows/doc.yml') }}
- name: Cache cargo binaries
uses: actions/cache@v1
with:
path: ~/.cargo/bin
key: ubuntu-latest-cargo-binaries-${{ hashFiles('.github/workflows/doc.yml') }}
- name: Install Bender and Morty
run: |
rustup update stable --no-self-update && rustup default stable
if ! $(which bender); then
cargo install bender --version 0.23.1
fi
if ! $(which morty); then
cargo install --git https://github.com/zarubaf/morty --rev 4855119c1378d45d9ac35cfa525725d2786e68f3
fi
shell: bash
- name: Build documentation
run: |
mkdir -p docs
morty -I include -I $(bender path common_cells)/include src/*.sv -d docs
shell: bash
- name: Determine documentation target folder
run: |
if [ "$GITHUB_EVENT_NAME" == "pull_request" ]; then
DOC_TARGET="$GITHUB_HEAD_REF"
elif [ "$GITHUB_EVENT_NAME" == "push" ]; then
if echo $GITHUB_REF | grep -qE '^refs/(head|tag)s'; then
DOC_TARGET="$(echo $GITHUB_REF | cut -d '/' -f3-)"
else
echo "Error: Could not derive documentation target folder for ref '$GITHUB_REF'!"
exit 1
fi
else
echo "Error: Unsupported event: '$GITHUB_EVENT_NAME'!"
exit 1
fi
echo "DOC_TARGET=$DOC_TARGET" >> $GITHUB_ENV
- name: Deploy documentation
uses: JamesIves/github-pages-deploy-action@releases/v3
if: >
github.event_name == 'push'
|| github.event.pull_request.head.repo.full_name == github.repository
with:
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
BRANCH: gh-pages # The branch the action should deploy to.
FOLDER: docs # The folder the action should deploy.
TARGET_FOLDER: ${{ env.DOC_TARGET }}
CLEAN: true # remove files from `TARGET_FOLDER` that are not in `FOLDER`
# (`rsync --delete`)
name: Retrieve CI result from GitLab
on:
push:
branches-ignore:
- gh-pages # deployment target branch (this workflow should not exist on that branch anyway)
- v** # such branch names conflict with tags
pull_request:
branches-ignore:
- gh-pages # deployment target branch (this workflow should not exist on that branch anyway)
- v** # such branch names conflict with tags
jobs:
gitlab-ci:
if: github.repository == 'pulp-platform/axi' # do not run this job on forks (because Gitlab CI
runs-on: ubuntu-latest # will not trigger on forks)
timeout-minutes: 190
steps:
- name: Checkout
uses: actions/checkout@v2
with:
persist-credentials: false
# Checkout pull request HEAD commit instead of merge commit, because CI runs against HEAD
# commit.
ref: ${{ github.event.pull_request.head.sha }}
- name: Wait for synchronization (every 5 minutes)
run: |
while [ $(($(date -d "+1 minute" +%-M) % 5)) -ne 0 ]; do
# "+1 minute" because if the current minute is divisible by 5, we likely already missed
# the synchronization.
sleep 10
done
sleep 90 # the minute above plus 30 seconds to leave some time for the synchronization
shell: bash
- name: Obtain CI result
run: |
if [ "$GITHUB_EVENT_NAME" == "pull_request" ]; then
BRANCH_NAME="$GITHUB_HEAD_REF"
elif [ "$GITHUB_EVENT_NAME" == "push" ]; then
if echo $GITHUB_REF | grep -qE '^refs/heads'; then
BRANCH_NAME="$(echo $GITHUB_REF | cut -d '/' -f3-)"
else
echo "Error: Could not derive branch name from ref '$GITHUB_REF'!"
exit 1
fi
else
echo "Error: Unsupported event: '$GITHUB_EVENT_NAME'!"
exit 1
fi
while true; do
resp="$(curl --fail --silent --show-error \
https://akurth.net/usrv/ig/shields/pipeline/akurth/axi/$BRANCH_NAME)"
if [ $? -ne 0 ]; then
echo "Error: Failed to obtain CI status!"
exit 1
fi
status="$(echo $resp | jq -r .message)"
if [ "$status" == "passing" ]; then
sha="$(echo $resp | jq -r .sha)"
if [ "$GITHUB_EVENT_NAME" == "pull_request" ]; then
github_sha="$(cat "$GITHUB_EVENT_PATH" | jq -r .pull_request.head.sha)"
else
github_sha="$GITHUB_SHA"
fi
if [ "$sha" == "$github_sha" ]; then
echo "CI passed."
exit 0
else
echo "Error: CI passed, but on a different SHA: '$sha'!"
exit 1
fi
elif [ "$status" == "running" ]; then
echo "CI is running, waiting .."
else
echo "Error: Unknown or failing status: '$status'!"
exit 1
fi
sleep 10
done
shell: bash
.*
!.git*
!.ci/
/.git/
/build
/Bender.lock
/Bender.local
#!/usr/bin/env bash
i=1
max_attempts=10
while ! memora "$@"; do
echo "Attempt $i/$max_attempts of 'memora $@' failed."
if test $i -ge $max_attempts; then
echo "'memora $@' keeps failing; aborting!"
exit 1
fi
i=$(($i+1))
done
variables:
SYNOPSYS_DC: synopsys-2019.12 dc_shell -64bit
before_script:
- export PATH=~/.cargo/bin:$PATH
- mkdir -p build
vsim:
stage: build
script:
- export ARTIFACT="vsim-$VSIM_VER"
- >
case $VSIM_VER in 20*)
export VSIM="questa-$VSIM_VER vsim -64";
export VLIB="questa-$VSIM_VER vlib";
export VLOG="questa-$VSIM_VER vlog -64";
;;
*)
export VSIM="vsim-$VSIM_VER -64";
export VLIB="vlib-$VSIM_VER";
export VLOG="vlog-$VSIM_VER -64";
;;
esac
- >
if ! $CI_PROJECT_DIR/.gitlab-ci.d/memora_retry.sh lookup $ARTIFACT; then
cd build && ../scripts/compile_vsim.sh && mv work{,-$VSIM_VER}
$CI_PROJECT_DIR/.gitlab-ci.d/memora_retry.sh insert $ARTIFACT
fi
parallel:
matrix:
- VSIM_VER: ['10.7b', '10.7e', '2020.1', '2021.1']
synopsys_dc:
stage: build
script:
- >
if ! $CI_PROJECT_DIR/.gitlab-ci.d/memora_retry.sh lookup synopsys_dc; then
cd build && ../scripts/synth.sh
$CI_PROJECT_DIR/.gitlab-ci.d/memora_retry.sh insert synopsys_dc
fi
.run_vsim: &run_vsim
stage: test
script:
- export ARTIFACT="$TEST_MODULE-vsim_$VSIM_VER"
- >
case $VSIM_VER in 20*)
export VSIM="questa-$VSIM_VER vsim -64";
;;
*)
export VSIM="vsim-$VSIM_VER -64";
;;
esac
- >
if ! $CI_PROJECT_DIR/.gitlab-ci.d/memora_retry.sh lookup $ARTIFACT; then
$CI_PROJECT_DIR/.gitlab-ci.d/memora_retry.sh get vsim-$VSIM_VER
cd build
mv work{-$VSIM_VER,}
../scripts/run_vsim.sh --random-seed $TEST_MODULE && touch $ARTIFACT.tested
$CI_PROJECT_DIR/.gitlab-ci.d/memora_retry.sh insert $ARTIFACT
fi
parallel:
matrix:
- VSIM_VER: ['10.7b', '10.7e', '2020.1', '2021.1']
axi_addr_test:
<<: *run_vsim
variables:
TEST_MODULE: axi_addr_test
axi_atop_filter:
<<: *run_vsim
variables:
TEST_MODULE: axi_atop_filter
axi_cdc:
<<: *run_vsim
variables:
TEST_MODULE: axi_cdc
axi_delayer:
<<: *run_vsim
variables:
TEST_MODULE: axi_delayer
axi_dw_downsizer:
<<: *run_vsim
variables:
TEST_MODULE: axi_dw_downsizer
axi_dw_upsizer:
<<: *run_vsim
variables:
TEST_MODULE: axi_dw_upsizer
axi_isolate:
<<: *run_vsim
variables:
TEST_MODULE: axi_isolate
axi_iw_converter:
<<: *run_vsim
variables:
TEST_MODULE: axi_iw_converter
axi_lite_regs:
<<: *run_vsim
variables:
TEST_MODULE: axi_lite_regs
axi_lite_to_apb:
<<: *run_vsim
variables:
TEST_MODULE: axi_lite_to_apb
axi_lite_to_axi:
<<: *run_vsim
variables:
TEST_MODULE: axi_lite_to_axi
axi_lite_mailbox:
<<: *run_vsim
variables:
TEST_MODULE: axi_lite_mailbox
axi_lite_xbar:
<<: *run_vsim
variables:
TEST_MODULE: axi_lite_xbar
axi_modify_address:
<<: *run_vsim
variables:
TEST_MODULE: axi_modify_address
axi_serializer:
<<: *run_vsim
variables:
TEST_MODULE: axi_serializer
axi_sim_mem:
<<: *run_vsim
variables:
TEST_MODULE: axi_sim_mem
axi_to_axi_lite:
<<: *run_vsim
variables:
TEST_MODULE: axi_to_axi_lite
axi_xbar:
<<: *run_vsim
variables:
TEST_MODULE: axi_xbar
package:
name: axi
authors:
- "Andreas Kurth <akurth@iis.ee.ethz.ch>" # current maintainer
- "Fabian Schuiki <fschuiki@iis.ee.ethz.ch>"
- "Florian Zaruba <zarubaf@iis.ee.ethz.ch>"
- "Matheus Cavalcante <matheusd@iis.ee.ethz.ch>"
- "Wolfgang Roenninger <wroennin@ethz.ch>"
dependencies:
common_cells: { git: "https://github.com/pulp-platform/common_cells.git", version: 1.21.0 }
common_verification: { git: "https://github.com/pulp-platform/common_verification.git", version: 0.2.0 }
export_include_dirs:
- include
sources:
# Source files grouped in levels. Files in level 0 have no dependencies on files in this
# package. Files in level 1 only depend on files in level 0, files in level 2 on files in
# levels 1 and 0, etc. Files within a level are ordered alphabetically.
# Level 0
- src/axi_pkg.sv
# Level 1
- src/axi_intf.sv
# Level 2
- src/axi_atop_filter.sv
- src/axi_burst_splitter.sv
- src/axi_cdc_dst.sv
- src/axi_cdc_src.sv
- src/axi_cut.sv
- src/axi_delayer.sv
- src/axi_demux.sv
- src/axi_dw_downsizer.sv
- src/axi_dw_upsizer.sv
- src/axi_id_remap.sv
- src/axi_id_prepend.sv
- src/axi_isolate.sv
- src/axi_join.sv
- src/axi_lite_demux.sv
- src/axi_lite_join.sv
- src/axi_lite_mailbox.sv
- src/axi_lite_mux.sv
- src/axi_lite_regs.sv
- src/axi_lite_to_apb.sv
- src/axi_lite_to_axi.sv
- src/axi_modify_address.sv
- src/axi_mux.sv
- src/axi_serializer.sv
# Level 3
- src/axi_cdc.sv
- src/axi_err_slv.sv
- src/axi_dw_converter.sv
- src/axi_id_serialize.sv
- src/axi_multicut.sv
- src/axi_to_axi_lite.sv
# Level 4
- src/axi_iw_converter.sv
- src/axi_lite_xbar.sv
- src/axi_xbar.sv
- target: synth_test
files:
- test/axi_synth_bench.sv
- target: simulation
files:
- src/axi_sim_mem.sv
- src/axi_test.sv
- target: test
files:
# Level 0
- test/tb_axi_dw_pkg.sv
- test/tb_axi_xbar_pkg.sv
# Level 1
- test/tb_axi_addr_test.sv
- test/tb_axi_atop_filter.sv
- test/tb_axi_cdc.sv
- test/tb_axi_delayer.sv
- test/tb_axi_dw_downsizer.sv
- test/tb_axi_dw_upsizer.sv
- test/tb_axi_isolate.sv
- test/tb_axi_lite_mailbox.sv
- test/tb_axi_lite_regs.sv
- test/tb_axi_iw_converter.sv
- test/tb_axi_lite_to_apb.sv
- test/tb_axi_lite_to_axi.sv
- test/tb_axi_lite_xbar.sv
- test/tb_axi_modify_address.sv
- test/tb_axi_serializer.sv
- test/tb_axi_sim_mem.sv
- test/tb_axi_to_axi_lite.sv
- test/tb_axi_xbar.sv
# Contribution Guidelines
## Coding Style
All SystemVerilog code in this repository _must_ adhere to the [SystemVerilog Coding Style Guide by
lowRISC](https://github.com/lowRISC/style-guides/blob/master/VerilogCodingStyle.md) and the
following rules:
- All module names _must_ start with `axi_`.
- User-facing modules _must_ have SystemVerilog `struct`s as AXI ports. The concrete `struct` type
_must_ be defined as `parameter` to the module. The fields of the `struct` _must_ correspond to
those defined by our [`typedef`
macros](https://github.com/pulp-platform/axi/blob/master/include/axi/typedef.svh).
- User-facing modules _may_ come with a variant that has SystemVerilog interfaces as AXI ports.
- Such an interface variant module _must not_ implement any functionality except wiring its
interfaces to the `struct` ports of the original module.
- The name of an interface variant _must_ be the name of the original module suffixed by `_intf`.
- The parameters of an interface variant must be formatted `ALL_CAPS`.
## Collaboration Guidelines
We follow [`pulp-platform`'s Collaboration
Guidelines](https://github.com/pulp-platform/style-guidelines/blob/master/CONTRIBUTING.md).
CAPI=2:
name : pulp-platform.org::axi:0.36.0
filesets:
rtl:
files:
- include/axi/assign.svh : {is_include_file : true, include_path : include}
- include/axi/typedef.svh : {is_include_file : true, include_path : include}
# Source files grouped in levels. Files in level 0 have no dependencies on files in this
# package. Files in level 1 only depend on files in level 0, files in level 2 on files in
# levels 1 and 0, etc. Files within a level are ordered alphabetically.
# Level 0
- src/axi_pkg.sv
# Level 1
- src/axi_intf.sv
# Level 2
- src/axi_atop_filter.sv
- src/axi_burst_splitter.sv
- src/axi_cdc_dst.sv
- src/axi_cdc_src.sv
- src/axi_cut.sv
- src/axi_delayer.sv
- src/axi_demux.sv
- src/axi_dw_downsizer.sv
- src/axi_dw_upsizer.sv
- src/axi_id_remap.sv
- src/axi_id_prepend.sv
- src/axi_isolate.sv
- src/axi_join.sv
- src/axi_lite_demux.sv
- src/axi_lite_join.sv
- src/axi_lite_mailbox.sv
- src/axi_lite_mux.sv
- src/axi_lite_regs.sv
- src/axi_lite_to_apb.sv
- src/axi_lite_to_axi.sv
- src/axi_modify_address.sv
- src/axi_mux.sv
- src/axi_serializer.sv
# Level 3
- src/axi_cdc.sv
- src/axi_err_slv.sv
- src/axi_dw_converter.sv
- src/axi_id_serialize.sv
- src/axi_multicut.sv
- src/axi_to_axi_lite.sv
# Level 4
- src/axi_iw_converter.sv
- src/axi_lite_xbar.sv
- src/axi_xbar.sv
file_type : systemVerilogSource
depend :
- ">=pulp-platform.org::common_cells:1.21.0"
generators:
axi_intercon_gen:
interpreter: python3
command: scripts/axi_intercon_gen.py
description: Generate a wrapper around PULP AXI xbar interconnect
usage: |
axi_intercon_gen wraps axi_xbar by expanding arrays of signals into
human-readable buses. Memory map can be set with generator parameters.
It will also generate a verilog include file containing the wire
definitions and module instantiation which can be `included in the
module where the interconnect wrapper is intended to be used.
Parameters:
masters: A dictionary where each key names a master interface connecting
to the interconnect and the associated value contains
configuration for that interface.
id_width (int): Width of the id signals for the master
slaves: A dictionary where each key names a slave interface connecting
to the interconnect and the associated value contains
configuration for that interface. The following configuration
keys are defined
offset (int): Base address for the slave
size (int): Size of the allocated memory map for the slave
Example usage:
The following config will generate an interconnect wrapper to which two
AXI4 master interfaces (dma and ibus) with different id widths are
connected, and connects downstream to three AXI4 slaves (rom, gpio, ram)
soc_intercon:
generator: axi_intercon_gen
parameters:
masters:
dma:
id_width : 1
ibus:
id_width : 2
slaves:
ram:
offset : 0
size: 0x10000000
gpio:
offset: 0x91000000
size: 0x1000
rom:
offset : 0xffff0000
size : 32768
targets:
default:
filesets : [rtl]
# Documentation of AXI Modules
This folder contains the documentation of the following modules:
- [AXI Crossbar (`axi_xbar`)](axi_xbar.md)
- [AXI Demultiplexer (`axi_demux`)](axi_demux.md)
- [AXI Multiplexer (`axi_mux`)](axi_mux.md)
- [AXI4-Lite Mailbox (`axi_lite_mailbox`)](axi_lite_mailbox.md)
## Relevant Specifications
We adhere to the *AMBA AXI and ACE Protocol Specification, Issue F.b*, abbreviated as *AXI Spec* in these documents.
## Terminology
We follow the terminology defined in the AXI Glossary (see p. 433 of the AXI Spec).
Additionally, we define the following terms.
### Handshake
On a channel with valid and ready signals, a *handshake* occurs when both valid and ready are high on a clock edge. See section A3.2.1 of the AXI Spec for details on the handshake process.
### In Flight
A transaction is *in flight* for a given interface when the handshake of the `Ax` beat of a transaction has occurred on that interface but the handshake of the (last) response of that transaction has not yet occurred on that interface.
### Pending
A handshake is *pending* for a given channel when the valid signal is high and the ready signal is low.
# AXI Demultiplexer
`axi_demux` splits one AXI connection into multiple ones. It implements the full AXI4 specification plus atomic operations (ATOPs) from AXI5.
## Design Overview
The demultiplexer has one *slave port* and a configurable number of *master ports*. A block diagram is shown below:
![Block diagram of the AXI demultiplexer](axi_demux.png "Block diagram of the AXI demultiplexer")
The AW and AR channels each have a *select* input, to determine the master port to which they are sent. The select can, for example, be driven by an (external) address decoder to map address ranges to different AXI slaves.
Beats on the W channel are routed by demultiplexer according to the selection for the corresponding AW beat. This relies on the AXI property that W bursts must be sent in the same order as AW beats and beats from different W bursts may not be interleaved.
Beats on the B and R channel are multiplexed from the master ports to the slave port with a round-robin arbitration tree.
## Configuration
This demultiplexer is configured through the parameters listed in the following table:
| Name | Type | Definition |
|:---------------------|:-------------------|:-----------|
| `AxiIdWidth` | `int unsigned` | The AXI ID width (of all ports). |
| `NoMstPorts` | `int unsigned` | The number of AXI master ports of the demultiplexer (in other words, how many AXI slave modules can be attached). |
| `MaxTrans` | `int unsigned` | The slave port can have at most this many transactions [in flight](../doc#in-flight). |
| `AxiLookBits` | `int unsigned` | The number of ID bits (starting at the least significant) the demultiplexer uses to determine the uniqueness of an AXI ID (see section *Ordering and Stalls* below). This value has to be less or equal than `AxiIdWidth`. |
| `UniqueIds` | `bit` | If you can guarantee that the ID of each transaction is always unique among all in-flight transactions in the same direction, setting this parameter to `1'b1` simplifies the demultiplexer (see section *Ordering and Stalls* below). Defaults to `1'b0`. |
| `FallThrough` | `bit` | Routing decisions on the AW channel fall through to the W channel. Enabling this allows the demultiplexer to accept a W beat in the same cycle as the corresponding AW beat, but it increases the combinatorial path of the W channel with logic from `slv_aw_select_i`. |
| `SpillXX` | `bit` | Inserts one spill register on the respective channel (AW, W, B, AR, and R) before the demultiplexer. |
The other parameters are types to define the ports of the demultiplexer. The `_*chan_t` types must be bound in accordance to the configuration using the `AXI_TYPEDEF` macros defined in `axi/typedef.svh`.
### Pipelining and Latency
The `SpillXX` parameters allow to insert spill register before each channel of the demultiplexer. Spill registers cut all combinatorial paths of a channel (i.e., both payload and handshake). Thus, they add one cycle of latency per channel but do not impair throughput.
If all `SpillXX` and `FallThrough` are disabled, all paths through this multiplexer are combinatorial (i.e., have zero sequential latency).
## Ports
| Name | Description |
|:----------------------------------|:------------|
| `clk_i` | Clock to which all other signals (except `rst_ni`) are synchronous. |
| `rst_ni` | Reset, asynchronous, active-low. |
| `test_i` | Test mode enable (active-high). |
| `slv_*` (except `slv_*_select_i`) | Single slave port of the demultiplexer. |
| `slv_{aw,ar}_select_i` | Index of the master port to which a write or read, respectively, is demultiplexed. This signal must be stable while a handshake on the AW respectively AR channel is [pending](../doc#pending). |
| `mst_*` | Array of master ports of the demultiplexer. The array index of each port is the index of the master port. |
## Ordering and Stalls
When the demultiplexer receives two transactions with the same ID and direction (i.e., both read or both write) but targeting two different master ports, it will not accept the second transaction until the first has completed. During this time, the demultiplexer stalls the AR or AW channel, respectively. To determine whether two transactions have the same ID, the `AxiLookBits` least-significant bits are compared. That parameter can be set to the full `AxiIdWidth` to avoid false ID conflicts, or it can be set to a lower value to reduce area and delay at the cost of more false conflicts.
The reason for this behavior are AXI ordering constraints, see the [documentation of the crossbar](axi_xbar.md#ordering-and-stalls) for details.
There are use cases that do not require the demultiplexer to keep track of and enforce this ordering, and the `UniqueIds` parameter can be set to specialize the demultiplexer for these cases:
`UniqueIds` may be set to `1'b1` if and only if
- each transaction has an ID that is unique among all in-flight transactions in the same direction;
- or for any ID, all transactions with that ID target the same master port as all other in-flight transactions with the same ID and direction;
- or both.
Setting the `UniqueIds` parameter to `1'b1` when those conditions are not always met leads to undefined behavior.
Setting the `UniqueIds` parameter to `1'b1` reduces the area complexity of the demultiplexer from `O(2^I)` to `O(I)`, where `I` is the ID width.
### Implementation
`2 * 2^AxiLookBits` counters track the number of [in-flight](../doc#in-flight) transactions. That is, for each ID in the (potentially) reduced set of IDs of `AxiLookBits` bits, there is one counter for write transactions and one for read transactions. Each counter can count up to (and including) `MaxTrans`, and there is a register that holds the index of the master port to which a counter is assigned.
When the demultiplexer gets an AW or an AR, it indexes the counters with the AXI ID. If the indexed counter has a value greater than zero and its master port index register is not equal to the index to which the AW or AR is to be sent, a transaction with the same direction and ID is already in flight to another master port. The demultiplexer then stalls the AW or AR. In all other cases, the demultiplexer forwards the AW or AR, increments the value of the indexed counter, and sets the master port index of the counter. A counter is decremented upon a handshake a B respectively last R beat at a slave port.
W beats are routed to the master port defined by the value of `slv_aw_select_i` for the corresponding AW. As the order of the W bursts is given by the order of the AWs, the select signals are stored in a FIFO queue. This FIFO is pushed upon a handshake on the AW slave channel and popped upon a handshake of the last W beat of a burst on a W master channel.
## Atomic Transactions
The demultiplexer also supports AXI atomic transactions (initiated by an AW with `atop` field not equal to zero). A part of AXI atomic transactions, namely atomic loads, require a response on the B *and* the R channel.
### Implementation
Atomic loads introduce a dependency between the read and write channels that otherwise does not exist in AXI. In this demultiplexer, the ID counters of the read channel must be aware of R beats without a corresponding AR. Otherwise, they would underflow upon atomic loads. To prevent this, the AW channel of the demultiplexer can "inject" the ID of an atomic load to the ID counter of the AR channel. This is possible because atomic transactions must have an ID that is unique with respect to *all* other transactions (i.e., reads *and* writes) currently in flight.
As only a part of the AXI ID is compared to determine whether two transactions have the same ID (see section *Ordering and Stalls*), atomic loads can lead to additional false conflict stalls on the read channel. However, atomic transactions are short bursts and thus usually complete relatively fast, so this should not reduce throughput under non-degenerate conditions.
# AXI4-Lite Demultiplexer
`axi_lite_demux` splits one AXI4-Lite connection into multiple ones.
## Design Overview
The demultiplexer has one *slave port* and a configurable number of *master ports*.
The AW and AR channels each have a *select* input, to determine the master port to which they are sent. The select can, for example, be driven by an (external) address decoder to map address ranges to different AXI4-Lite slaves.
Beats on the W channel are routed by the demultiplexer with the same selection as the corresponding AW beat.
Beats on the B and R channel are multiplexed from the master ports by the switching decision saved in their respective FIFO's.
## Configuration
This demultiplexer is configured through the parameters listed in the following table:
| Name | Type | Definition |
|:---------------------|:-------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `NoMstPorts` | `int unsigned` | The number of AXI4-Lite master ports of the demultiplexer (in other words, how many AXI4-Lite slave modules can be attached). |
| `MaxTrans` | `int unsigned` | The slave port can have at most this many transactions [in flight](../doc#in-flight). |
| `FallThrough` | `bit` | Routing decisions on the AW channel fall through to the W channel (i.e. don't consume a cycle). Enabling this allows the demultiplexer to accept a W beat in the same cycle as the corresponding AW beat, but it increases the combinatorial path of the W channel with logic from `slv_aw_select_i`. |
| `SpillXX` | `bit` | Inserts one spill register on the respective channel (AW, W, B, AR, and R) before the demultiplexer. |
The other parameters are types to define the ports of the demultiplexer. The `_*chan_t` types must be bound in accordance to the configuration using the `AXI_TYPEDEF` macros defined in `axi/typedef.svh`.
### Pipelining and Latency
The `SpillXX` parameters allow to insert spill register before each channel of the demultiplexer. Spill registers cut all combinatorial paths of a channel (i.e., both payload and handshake). Thus, they add one cycle of latency per channel but do not impair throughput.
If all `SpillXX` and `FallThrough` are disabled, all paths through this multiplexer are combinatorial (i.e., have zero latency).
## Ports
| Name | Description |
|:----------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `clk_i` | Clock to which all other signals (except `rst_ni`) are synchronous. |
| `rst_ni` | Reset, asynchronous, active-low. |
| `test_i` | Test mode enable (active-high). |
| `slv_*` (except `slv_*_select_i`) | Single slave port of the demultiplexer. |
| `slv_{aw,ar}_select_i` | Index of the master port to which a write or read, respectively, is demultiplexed. This signal must be stable while a handshake on the AW respectively AR channel is [pending](../doc#pending). |
| `mst_*` | Array of master ports of the demultiplexer. The array index of each port is the index of the master port. |
### Implementation
W beats are routed to the master port defined by the value of `slv_aw_select_i` for the corresponding AW. As the order of the W transactions is given by the order of the AWs, the select signals are stored in a FIFO. This FIFO is pushed upon a handshake on the AW slave channel and popped upon a handshake of the corresponding W transaction.
The demultiplexer saves the routing decision in their respective FIFO for the response routing.
# AXI4-Lite Multiplexer
The opposite function to the AXI4-Lite demultiplexer is performed by the AXI4-Lite Multiplexer. It merges multiple AXI4-Lite connections into one. The requests from multiple slave ports get interleaved and transmitted over a single master port.
![Block-diagram of the AXI4-Lite Multiplexer Module.](axi_lite_mux.png "Block-diagram of the AXI4-Lite Multiplexer Module.")
The requests on the AW and AR channels each get merged with round robin arbitration. The arbitration decision is stored in the FIFO's which handle the response routing.
The following table shows the parameters of the module. The module further requires the structs describing the five AXI4-Lite channels.
| Name | Type | Function |
|:--------------|:---------------|:---------------------------------------------------------------------------------------------------------------|
| `NoSlvPorts` | `int unsigned` | How many slave ports the multiplexer features. This many master modules can be connected to the multiplexer. |
| `MaxWTrans` | `int unsigned` | The depth of the FIFO holding the highest bits of the ID between the AW and W channel. |
| `FallThrough` | `bit` | Is the FIFO between the AW and W channel in fall-through mode. Enabling will lead to an additional delay cycle |
| `SpillXX` | `bit` | Enables the optional spill-register on the respective channel. |
# AXI Multiplexer
The opposite function to the AXI demultiplexer is performed by the AXI Multiplexer. It merges multiple AXI-4 connections and merges them into one. The requests from multiple slave ports of the module get interleaved and transmitted over its one master port.
![Block-diagram of the AXI 4 Multiplexer Module.](axi_mux.png "Block-diagram of the AXI 4 Multiplexer Module.")
The Multiplexer module is has a simpler structure than the demultiplexer introduced in the previous section. The requests on the AW and AR channels get merged with the same round robin arbitration used for merging the responses in the demultiplexer. One key difference however is the mechanism how the multiplexer determines from which slave port a request came. It uses for this the higher bits of the `axi_id` field of a request. The number of bits can be calculated with:
```systemverilog
$clog2(NoSlavePorts)
```
This restricts the type of ID which can be sent through each slave port of the module. When the higher ID bits do not correspond to the index of the port the following response will be sent back through to the wrong master, leading to a breakdown of the functionality. So for using this module it is recommended to extend each AXI ID by the required amount of bits indicating the index of the respective slave port, before being sent over this module.
For a write transaction the W beats belonging to an AW request have to be sent in order. For this the highest bits of the `aw_id` get pushed into a FIFO. When the FIFO is not empty the data determines which W slave port gets connected to the master port. When the last beat of a write transaction is sent, the data gets poped.
All responses get routed with the same scheme for tracking to which slave port a response should be sent. If the module has a response ready at its master port it connects the respective slave port indicated by the AXI ID.
The reason the switching is done this way is that again, the ordering model of the AXI protocol has to be respected. By using the extended ID it further helps to decouple requests from different master modules connected to the Multiplexer. It ensures that each master module has its unique set of AXI ID's, leading to potential performance increases when different masters are using vastly different burst lengths. As this could enable a slave module to interleave the responses.
Another reason, why the switching of the responses is done over the ID is the required atomic transaction support. The protocol specifies that a master module has to ensure that a atomic transaction uses a different ID than normal transactions already in flight. This is to prevent ordering requirements between atomic transaction and normal ones. Another problem is further again that an atomic transaction can lead to a response in the B and R channel, further defining a dependence between the read and write channels.
Using an ID prefix for the switching in the multiplexer prevents that this module has to deal with the ordering requirements between these different types of instructions. The responsibility gets put to the master module connected to the slave port of the multiplexer.
The following table shows the parameters of the module. The module further requires the structs describing the five AXI channels.
| Name | Type | Function |
|:------------------ |:----------------- |:---------------------------------- |
| `AxiIdWidth` | `int unsigned` | The width of the AXI transaction ID in bits. |
| `NoSlvPorts` | `int unsigned` | How many slave ports the multiplexer features. This many master modules can be connected to the multiplexer.|
| `MaxWTrans` | `int unsigned` | The depth of the FIFO holding the highest bits of the ID between the AW and W channel. |
| `FallThrough` | `bit` | Is the FIFO between the AW and W channel in fall-through mode. Enabling will lead to longer cycle delays. |
| `SpillXX` | `bit` | Enables the optional spill-register on the respective channel. |
The ports of the multiplexer module are defined by the AXI4 channel structs. The module features only the respective slaves and master port, as the switching happens over the highest bits of the AXI ID.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
common_cells:
commit: v1.21.0
group: pulp-platform
common_verification:
commit: v0.2.0
group: pulp-platform
#!/bin/bash
# Copyright (c) 2014-2018 ETH Zurich, University of Bologna
#
# Copyright and related rights are licensed under the Solderpad Hardware
# License, Version 0.51 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
# or agreed to in writing, software, hardware and materials distributed under
# this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
#
# Authors:
# - Andreas Kurth <akurth@iis.ee.ethz.ch>
# - Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
set -e
[ ! -z "$VSIM" ] || VSIM=vsim
bender script vsim -t test \
--vlog-arg="-svinputport=compat" \
--vlog-arg="-override_timescale 1ns/1ps" \
--vlog-arg="-suppress 2583" \
> compile.tcl
echo 'return 0' >> compile.tcl
# Add `-lint -pendanticerrors` flags only for the files in this repository.
# Patching the compile script in this way is quite ugly, maybe there should be a Bender command to
# add arguments just for certain targets.
for x in axi_pkg; do
# Adapted from https://unix.stackexchange.com/a/200610.
POSIXLY_CORRECT=1 awk -v N=6 "
BEGIN{N--}
NR > N {
if (/.*src\/$x\.sv/)
print \" -lint -pedanticerrors \\\\\"
print l[NR % N]
}
{l[NR % N] = \$0}
END{
for (i = NR > N ? NR - N + 1 : 1; i <= NR; i++) print l[i % N]
}" < compile.tcl > compile.patched.tcl
mv compile{.patched,}.tcl
done
$VSIM -c -do 'exit -code [source compile.tcl]'
#!/bin/bash
# Copyright (c) 2021 ETH Zurich, University of Bologna
#
# Copyright and related rights are licensed under the Solderpad Hardware
# License, Version 0.51 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
# or agreed to in writing, software, hardware and materials distributed under
# this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
set -e
ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
[ ! -z "$VERILATOR" ] || VERILATOR="verilator"
bender script verilator -t synthesis -t synth_test > ./verilator.f
VERILATOR_FLAGS=()
VERILATOR_FLAGS+=(-Wno-fatal)
$VERILATOR --top-module axi_synth_bench --lint-only -f verilator.f ${VERILATOR_FLAGS[@]}
#!/bin/bash
# Copyright (c) 2014-2018 ETH Zurich, University of Bologna
#
# Copyright and related rights are licensed under the Solderpad Hardware
# License, Version 0.51 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
# or agreed to in writing, software, hardware and materials distributed under
# this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
#
# Authors:
# - Andreas Kurth <akurth@iis.ee.ethz.ch>
# - Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
# - Matheus Cavalcante <matheusd@iis.ee.ethz.ch>
set -euo pipefail
ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
if test -z ${VSIM+x}; then
VSIM=vsim
fi
# Seed values for `sv_seed`; can be extended with specific values on a per-TB basis, as well as with
# a random number by passing the `--random` flag. The default value, 0, is always included to stay
# regression-consistent.
SEEDS=(0)
call_vsim() {
for seed in ${SEEDS[@]}; do
echo "run -all" | $VSIM -sv_seed $seed "$@" | tee vsim.log 2>&1
grep "Errors: 0," vsim.log
done
}
exec_test() {
if [ ! -e "$ROOT/test/tb_$1.sv" ]; then
echo "Testbench for '$1' not found!"
exit 1
fi
case "$1" in
axi_atop_filter)
for MAX_TXNS in 1 3 12; do
call_vsim tb_axi_atop_filter -gTB_N_TXNS=1000 -gTB_AXI_MAX_WRITE_TXNS=$MAX_TXNS
done
;;
axi_cdc|axi_delayer)
call_vsim tb_$1
;;
axi_dw_downsizer)
for AxiSlvPortDataWidth in 8 16 32 64 128 256 512 1024; do
for (( AxiMstPortDataWidth = 8; \
AxiMstPortDataWidth < $AxiSlvPortDataWidth; \
AxiMstPortDataWidth *= 2 )); \
do
call_vsim tb_axi_dw_downsizer \
-gTbAxiSlvPortDataWidth=$AxiSlvPortDataWidth \
-gTbAxiMstPortDataWidth=$AxiMstPortDataWidth -t 1ps
done
done
;;
axi_dw_upsizer)
for AxiSlvPortDataWidth in 8 16 32 64 128 256 512 1024; do
for (( AxiMstPortDataWidth = $AxiSlvPortDataWidth*2; \
AxiMstPortDataWidth <= 1024; \
AxiMstPortDataWidth *= 2 )); \
do
call_vsim tb_axi_dw_upsizer \
-gTbAxiSlvPortDataWidth=$AxiSlvPortDataWidth \
-gTbAxiMstPortDataWidth=$AxiMstPortDataWidth -t 1ps
done
done
;;
axi_iw_converter)
for SLV_PORT_IW in 1 2 3 4 8; do
MAX_SLV_PORT_IDS=$((2**SLV_PORT_IW))
MAX_UNIQ_SLV_PORT_IDS_OPTS=(1 2)
EXCL_OPTS=(0)
if [ $SLV_PORT_IW -eq 3 ]; then
# Save time by not testing exclusive accesses for every parametrization.
EXCL_OPTS+=(1)
fi
for EXCL in "${EXCL_OPTS[@]}"; do
if [ $MAX_SLV_PORT_IDS -gt 2 ]; then
MAX_UNIQ_SLV_PORT_IDS_OPTS+=(3 4)
fi
if [ $(($MAX_SLV_PORT_IDS/2)) -ge 4 ]; then
MAX_UNIQ_SLV_PORT_IDS_OPTS+=($((MAX_SLV_PORT_IDS/2-1)))
fi
MAX_UNIQ_SLV_PORT_IDS_OPTS+=($MAX_SLV_PORT_IDS)
for MST_PORT_IW in 1 2 3 4; do
if [ $MST_PORT_IW -lt $SLV_PORT_IW ]; then # downsize
for MAX_UNIQ_SLV_PORT_IDS in "${MAX_UNIQ_SLV_PORT_IDS_OPTS[@]}"; do
MAX_MST_PORT_IDS=$((2**MST_PORT_IW))
if [ $MAX_UNIQ_SLV_PORT_IDS -le $MAX_MST_PORT_IDS ]; then
call_vsim tb_axi_iw_converter \
-t 1ns -coverage -classdebug \
-voptargs="+acc +cover=bcesfx" \
-GTbEnExcl=$EXCL \
-GTbAxiSlvPortIdWidth=$SLV_PORT_IW \
-GTbAxiMstPortIdWidth=$MST_PORT_IW \
-GTbAxiSlvPortMaxUniqIds=$MAX_UNIQ_SLV_PORT_IDS \
-GTbAxiSlvPortMaxTxnsPerId=5
else
call_vsim tb_axi_iw_converter \
-t 1ns -coverage -classdebug \
-voptargs="+acc +cover=bcesfx" \
-GTbEnExcl=$EXCL \
-GTbAxiSlvPortIdWidth=$SLV_PORT_IW \
-GTbAxiMstPortIdWidth=$MST_PORT_IW \
-GTbAxiSlvPortMaxUniqIds=$MAX_UNIQ_SLV_PORT_IDS \
-GTbAxiSlvPortMaxTxns=31 \
-GTbAxiMstPortMaxUniqIds=$((2**MST_PORT_IW)) \
-GTbAxiMstPortMaxTxnsPerId=7
fi
done
else
call_vsim tb_axi_iw_converter \
-t 1ns -coverage -classdebug \
-voptargs="+acc +cover=bcesfx" \
-GTbEnExcl=$EXCL \
-GTbAxiSlvPortIdWidth=$SLV_PORT_IW \
-GTbAxiMstPortIdWidth=$MST_PORT_IW \
-GTbAxiSlvPortMaxTxnsPerId=3
fi
done
done
done
;;
axi_lite_regs)
SEEDS+=(10 42)
for PRIV in 0 1; do
for SECU in 0 1; do
for BYTES in 42 200 369; do
call_vsim tb_axi_lite_regs -gTbPrivProtOnly=$PRIV -gTbSecuProtOnly=$SECU \
-gTbRegNumBytes=$BYTES -t 1ps
done
done
done
;;
axi_lite_to_apb)
for PIPE_REQ in 0 1; do
for PIPE_RESP in 0 1; do
call_vsim tb_axi_lite_to_apb -gTbPipelineRequest=$PIPE_REQ \
-gTbPipelineResponse=$PIPE_RESP
done
done
;;
axi_lite_to_axi)
for DW in 8 16 32 64 128 256 512 1024; do
call_vsim tb_axi_lite_to_axi -gTB_DW=$DW -t 1ps
done
;;
axi_sim_mem)
for AW in 16 32 64; do
for DW in 32 64 128 256 512 1024; do
call_vsim tb_axi_sim_mem -gTbAddrWidth=$AW -gTbDataWidth=$DW -t 1ps
done
done
;;
axi_xbar)
for NumMst in 1 6; do
for NumSlv in 1 8; do
for Atop in 0 1; do
for Exclusive in 0 1; do
for UniqueIds in 0 1; do
call_vsim tb_axi_xbar -gTbNumMst=$NumMst -gTbNumSlv=$NumSlv \
-gTbEnAtop=$Atop -gTbEnExcl=$Exclusive \
-gTbUniqueIds=$UniqueIds
done
done
done
done
done
;;
*)
call_vsim tb_$1 -t 1ns -coverage -voptargs="+acc +cover=bcesfx"
;;
esac
}
# Parse flags.
PARAMS=""
while (( "$#" )); do
case "$1" in
--random-seed)
SEEDS+=(random)
shift;;
-*--*) # unsupported flag
echo "Error: Unsupported flag '$1'." >&2
exit 1;;
*) # preserve positional arguments
PARAMS="$PARAMS $1"
shift;;
esac
done
eval set -- "$PARAMS"
if [ "$#" -eq 0 ]; then
tests=()
while IFS= read -r -d $'\0'; do
tb_name="$(basename -s .sv $REPLY)"
dut_name="${tb_name#tb_}"
tests+=("$dut_name")
done < <(find "$ROOT/test" -name 'tb_*.sv' -a \( ! -name '*_pkg.sv' \) -print0)
else
tests=("$@")
fi
for t in "${tests[@]}"; do
exec_test $t
done
#!/bin/bash
# Copyright (c) 2014-2018 ETH Zurich, University of Bologna
#
# Copyright and related rights are licensed under the Solderpad Hardware
# License, Version 0.51 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
# or agreed to in writing, software, hardware and materials distributed under
# this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
#
# Authors:
# - Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
# - Andreas Kurth <akurth@iis.ee.ethz.ch>
set -e
ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
[ ! -z "$SYNOPSYS_DC" ] || SYNOPSYS_DC="synopsys dc_shell -64"
echo 'remove_design -all' > ./synth.tcl
bender script synopsys -t synth_test >> ./synth.tcl
echo 'elaborate axi_synth_bench' >> ./synth.tcl
cat ./synth.tcl | $SYNOPSYS_DC | tee synth.log 2>&1
grep -i "warning:" synth.log || true
grep -i "error:" synth.log && false
touch synth.completed
#!/usr/bin/env bash
#
# Copyright (c) 2021 ETH Zurich, University of Bologna
# SPDX-License-Identifier: Apache-2.0
#
# Authors:
# - Andreas Kurth <akurth@iis.ee.ethz.ch>
set -euo pipefail
stderr() {
printf "$@" >&2
}
# Some authors prefer to not appear with real name and email address in author lists.
declare -A hide=( \
)
# Map each author name to an email address.
declare -A emails=( \
["Andreas Kurth"]="akurth@iis.ee.ethz.ch" \
["Fabian Schuiki"]="fschuiki@iis.ee.ethz.ch" \
["Florian Zaruba"]="zarubaf@iis.ee.ethz.ch" \
["Matheus Cavalcante"]="matheusd@iis.ee.ethz.ch" \
["Samuel Riedel"]="sriedel@iis.ee.ethz.ch" \
["Stefan Mach"]="smach@iis.ee.ethz.ch" \
["Wolfgang Rönninger"]="wroennin@iis.ee.ethz.ch" \
)
# Iterate over source files (see `done` line for which files are included).
while IFS= read -r -d $'\0' file; do
if $(echo "$file" | grep -q '\.svh\?$'); then # SystemVerilog file
comment_lead='//'
comment_lead_escaped='\/\/'
else
comment_lead='#'
comment_lead_escaped='#'
fi
re_authors="^\\s*${comment_lead}\\s*Authors:\$"
# If the file does not contain an 'Authors:' paragraph, create one.
if ! grep -q "$re_authors" "$file"; then
# Find first line after copyright header.
copyright_end=$(awk "BEGIN {newparagraph=1;}
{
if (newparagraph) {
if (\$0 ~ /^${comment_lead_escaped}\\s*[cC]opyright/) {
newparagraph=0;
next
} else {
print NR;
exit
}
} else if (\$0 ~ /^\\/*$/) {
newparagraph=1;
next
}
}" "$file")
# Insert 'Authors:' header.
sed -i -e "${copyright_end}a${comment_lead} Authors:" "$file"
fi
# Find line before and after authors list.
authors_begin=$(grep -n -m 1 "$re_authors" $file | sed 's/\([0-9]\+\).*/\1/')
authors_end=$(awk "{if (NR > $authors_begin && \$0 ~ /^\$/) {print NR; exit}}" "$file")
# Replace author list with information from `git log`.
tmpfile=$(mktemp)
{
sed -n "1,${authors_begin}p" "$file"
readarray -t changes <<<"$(git log --follow --numstat --format='%an' "$file" | awk '
BEGIN {totalchange=0; }
{
if (NR % 3 == 1) {
author=$0;
} else if (NR % 3 == 0) {
if (!change[author]) {
change[author]=0;
}
change[author]+=$1;
totalchange+=$1
change[author]+=$2;
totalchange+=$2;
}
}
END {
print totalchange;
for (author in change) {
print change[author] " " author;
}
}')"
totalchange="${changes[0]}"
authorchanges=()
for authorchange in "${changes[@]:1}"; do
name="$(echo "$authorchange" | cut -d' ' -f 2-)"
change="$(echo "$authorchange" | cut -d' ' -f 1)"
# Only list authors who have contributed to more than 5% of the changes in the file.
if test $(( $change * 100 / $totalchange )) -ge 5; then
authorchanges+=("$change $name")
fi
done
# Sort author with most changes first.
readarray -t authors < <(printf '%s\n' "${authorchanges[@]}" | sort -nr)
stderr "$file\n"
stderr '%s\n' "${authors[@]}"
stderr '\n'
readarray -t authors < <(printf '%s\n' "${authors[@]}" | cut -d' ' -f2-)
for author in "${authors[@]}"; do
if ! "${hide[$author]:-false}"; then
if ! test ${emails[$author]+_}; then
stderr "Error: Email address of author '$author' unknown!\n"
exit 1
fi
email="${emails[$author]}"
author_ascii=$(echo "$author" | sed 's/ö/oe/g')
if $(echo "$author_ascii" | grep -q -P '[^[:ascii:]]'); then
stderr "Author name '$author_ascii' contains a non-ASCII character!\n"
exit 1
fi
echo "$comment_lead - $author_ascii <$email>"
fi
done
sed -n "$authors_end,\$p" "$file"
} > "$tmpfile"
chmod --reference="$file" "$tmpfile" # retain file permissions
mv "$tmpfile" "$file"
done < <(git ls-tree -r -z --name-only HEAD -- 'include' 'scripts' 'src' 'test' \
| grep -z -P '\.s(?:vh?|h)$|^(?!.+\.)')
# left alternative matches files with .sh, .sv, and .svh extensions;
# right alternative matches files with no extension
class Signal(object):
def __init__(self, name, width=0, low=0, asc=False, vec=0):
self.name = name
self.width=width
self.low = low
self.asc = asc
def range(self):
if self.width > 0:
l = self.width+self.low-1
r = self.low
if self.asc:
return '['+str(r)+':'+str(l)+']'
else:
return '['+str(l)+':'+str(r)+']'
return ''
class Wire(Signal):
def write(self, width):
return 'wire{range} {name};\n'.format(range=self.range().rjust(width), name=self.name)
class Port:
def __init__(self, name, value):
self.name = name
self.value = value
class ModulePort(Signal):
def __init__(self, name, dir, width=0, low=0, asc=False):
super(ModulePort, self).__init__(name, width, low, asc)
self.dir = dir
def write(self, range_width=0):
return '{dir} wire {range} {name}'.format(dir=self.dir.ljust(6), range=self.range().rjust(range_width), name=self.name)
class Instance:
def __init__(self, module, name, parameters, ports):
self.module = module
self.name = name
self.parameters = parameters
self.ports = ports
def write(self):
s = self.module
if self.parameters:
max_len = max([len(p.name) for p in self.parameters])
s += '\n #('
s += ',\n '.join(['.' + p.name.ljust(max_len) +' (' + str(p.value) + ')' for p in self.parameters])
s += ')\n'
s += ' ' + self.name
if self.ports:
s += '\n ('
max_len = max([len(p.name) for p in self.ports])
s += ',\n '.join(['.' + p.name.ljust(max_len) +' (' + str(p.value) + ')' for p in self.ports])
s += ')'
s += ';\n'
return s
class VerilogWriter:
raw = ""
def __init__(self, name):
self.name = name
self.instances = []
self.ports = []
self.wires = []
def add(self, obj):
if isinstance(obj, Instance):
self.instances += [obj]
elif isinstance(obj, ModulePort):
self.ports += [obj]
elif isinstance(obj, Wire):
self.wires += [obj]
else:
raise Exception("Invalid type!" + str(obj))
def write(self, file=None):
s = ("// THIS FILE IS AUTOGENERATED BY axi_intercon_gen\n"
"// ANY MANUAL CHANGES WILL BE LOST\n")
if self.ports:
s += "`default_nettype none\n"
s += "module {name}\n".format(name=self.name)
max_len = max([len(p.range()) for p in self.ports])
s += ' ('
s += ',\n '.join([p.write(max_len) for p in self.ports])
s += ')'
s += ';\n\n'
if self.wires:
max_len = max([len(w.range()) for w in self.wires])
for w in self.wires:
s += w.write(max_len + 1)
s +='\n'
s += self.raw
for i in self.instances:
s += i.write()
s += '\n'
if self.ports:
s += 'endmodule\n'
if file is None:
return s
else:
f = open(file,'w')
f.write(s)
// Copyright (c) 2019-2020 ETH Zurich, University of Bologna
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Authors:
// - Andreas Kurth <akurth@iis.ee.ethz.ch>
// - Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
// - Florian Zaruba <zarubaf@iis.ee.ethz.ch>
// - Wolfgang Roenninger <wroennin@iis.ee.ethz.ch>
// - Luca Valente <luca.valente2@unibo.it>
`include "axi/assign.svh"
/// A clock domain crossing on an AXI interface.
///
/// For each of the five AXI channels, this module instantiates a CDC FIFO, whose push and pop
/// ports are in separate clock domains. IMPORTANT: For each AXI channel, you MUST properly
/// constrain three paths through the FIFO; see the header of `cdc_fifo_gray` for instructions.
module axi_cdc #(
parameter type aw_chan_t = logic, // AW Channel Type
parameter type w_chan_t = logic, // W Channel Type
parameter type b_chan_t = logic, // B Channel Type
parameter type ar_chan_t = logic, // AR Channel Type
parameter type r_chan_t = logic, // R Channel Type
parameter type axi_req_t = logic, // encapsulates request channels
parameter type axi_resp_t = logic, // encapsulates request channels
/// Depth of the FIFO crossing the clock domain, given as 2**LOG_DEPTH.
parameter int unsigned LogDepth = 1
) (
// slave side - clocked by `src_clk_i`
input logic src_clk_i,
input logic src_rst_ni,
input axi_req_t src_req_i,
output axi_resp_t src_resp_o,
// master side - clocked by `dst_clk_i`
input logic dst_clk_i,
input logic dst_rst_ni,
output axi_req_t dst_req_o,
input axi_resp_t dst_resp_i
);
aw_chan_t [2**LogDepth-1:0] async_data_aw_data;
w_chan_t [2**LogDepth-1:0] async_data_w_data;
b_chan_t [2**LogDepth-1:0] async_data_b_data;
ar_chan_t [2**LogDepth-1:0] async_data_ar_data;
r_chan_t [2**LogDepth-1:0] async_data_r_data;
logic [LogDepth:0] async_data_aw_wptr, async_data_aw_rptr,
async_data_w_wptr, async_data_w_rptr,
async_data_b_wptr, async_data_b_rptr,
async_data_ar_wptr, async_data_ar_rptr,
async_data_r_wptr, async_data_r_rptr;
axi_cdc_src #(
.aw_chan_t ( aw_chan_t ),
.w_chan_t ( w_chan_t ),
.b_chan_t ( b_chan_t ),
.ar_chan_t ( ar_chan_t ),
.r_chan_t ( r_chan_t ),
.axi_req_t ( axi_req_t ),
.axi_resp_t ( axi_resp_t ),
.LogDepth ( LogDepth )
) i_axi_cdc_src (
.src_clk_i,
.src_rst_ni,
.src_req_i,
.src_resp_o,
(* async *) .async_data_master_aw_data_o ( async_data_aw_data ),
(* async *) .async_data_master_aw_wptr_o ( async_data_aw_wptr ),
(* async *) .async_data_master_aw_rptr_i ( async_data_aw_rptr ),
(* async *) .async_data_master_w_data_o ( async_data_w_data ),
(* async *) .async_data_master_w_wptr_o ( async_data_w_wptr ),
(* async *) .async_data_master_w_rptr_i ( async_data_w_rptr ),
(* async *) .async_data_master_b_data_i ( async_data_b_data ),
(* async *) .async_data_master_b_wptr_i ( async_data_b_wptr ),
(* async *) .async_data_master_b_rptr_o ( async_data_b_rptr ),
(* async *) .async_data_master_ar_data_o ( async_data_ar_data ),
(* async *) .async_data_master_ar_wptr_o ( async_data_ar_wptr ),
(* async *) .async_data_master_ar_rptr_i ( async_data_ar_rptr ),
(* async *) .async_data_master_r_data_i ( async_data_r_data ),
(* async *) .async_data_master_r_wptr_i ( async_data_r_wptr ),
(* async *) .async_data_master_r_rptr_o ( async_data_r_rptr )
);
axi_cdc_dst #(
.aw_chan_t ( aw_chan_t ),
.w_chan_t ( w_chan_t ),
.b_chan_t ( b_chan_t ),
.ar_chan_t ( ar_chan_t ),
.r_chan_t ( r_chan_t ),
.axi_req_t ( axi_req_t ),
.axi_resp_t ( axi_resp_t ),
.LogDepth ( LogDepth )
) i_axi_cdc_dst (
.dst_clk_i,
.dst_rst_ni,
.dst_req_o,
.dst_resp_i,
(* async *) .async_data_slave_aw_wptr_i ( async_data_aw_wptr ),
(* async *) .async_data_slave_aw_rptr_o ( async_data_aw_rptr ),
(* async *) .async_data_slave_aw_data_i ( async_data_aw_data ),
(* async *) .async_data_slave_w_wptr_i ( async_data_w_wptr ),
(* async *) .async_data_slave_w_rptr_o ( async_data_w_rptr ),
(* async *) .async_data_slave_w_data_i ( async_data_w_data ),
(* async *) .async_data_slave_b_wptr_o ( async_data_b_wptr ),
(* async *) .async_data_slave_b_rptr_i ( async_data_b_rptr ),
(* async *) .async_data_slave_b_data_o ( async_data_b_data ),
(* async *) .async_data_slave_ar_wptr_i ( async_data_ar_wptr ),
(* async *) .async_data_slave_ar_rptr_o ( async_data_ar_rptr ),
(* async *) .async_data_slave_ar_data_i ( async_data_ar_data ),
(* async *) .async_data_slave_r_wptr_o ( async_data_r_wptr ),
(* async *) .async_data_slave_r_rptr_i ( async_data_r_rptr ),
(* async *) .async_data_slave_r_data_o ( async_data_r_data )
);
endmodule
`include "axi/assign.svh"
`include "axi/typedef.svh"
// interface wrapper
module axi_cdc_intf #(
parameter int unsigned AXI_ID_WIDTH = 0,
parameter int unsigned AXI_ADDR_WIDTH = 0,
parameter int unsigned AXI_DATA_WIDTH = 0,
parameter int unsigned AXI_USER_WIDTH = 0,
/// Depth of the FIFO crossing the clock domain, given as 2**LOG_DEPTH.
parameter int unsigned LOG_DEPTH = 1
) (
// slave side - clocked by `src_clk_i`
input logic src_clk_i,
input logic src_rst_ni,
AXI_BUS.Slave src,
// master side - clocked by `dst_clk_i`
input logic dst_clk_i,
input logic dst_rst_ni,
AXI_BUS.Master dst
);
typedef logic [AXI_ID_WIDTH-1:0] id_t;
typedef logic [AXI_ADDR_WIDTH-1:0] addr_t;
typedef logic [AXI_DATA_WIDTH-1:0] data_t;
typedef logic [AXI_DATA_WIDTH/8-1:0] strb_t;
typedef logic [AXI_USER_WIDTH-1:0] user_t;
`AXI_TYPEDEF_AW_CHAN_T(aw_chan_t, addr_t, id_t, user_t)
`AXI_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t, user_t)
`AXI_TYPEDEF_B_CHAN_T(b_chan_t, id_t, user_t)
`AXI_TYPEDEF_AR_CHAN_T(ar_chan_t, addr_t, id_t, user_t)
`AXI_TYPEDEF_R_CHAN_T(r_chan_t, data_t, id_t, user_t)
`AXI_TYPEDEF_REQ_T(req_t, aw_chan_t, w_chan_t, ar_chan_t)
`AXI_TYPEDEF_RESP_T(resp_t, b_chan_t, r_chan_t)
req_t src_req, dst_req;
resp_t src_resp, dst_resp;
`AXI_ASSIGN_TO_REQ(src_req, src)
`AXI_ASSIGN_FROM_RESP(src, src_resp)
`AXI_ASSIGN_FROM_REQ(dst, dst_req)
`AXI_ASSIGN_TO_RESP(dst_resp, dst)
axi_cdc #(
.aw_chan_t ( aw_chan_t ),
.w_chan_t ( w_chan_t ),
.b_chan_t ( b_chan_t ),
.ar_chan_t ( ar_chan_t ),
.r_chan_t ( r_chan_t ),
.axi_req_t ( req_t ),
.axi_resp_t ( resp_t ),
.LogDepth ( LOG_DEPTH )
) i_axi_cdc (
.src_clk_i,
.src_rst_ni,
.src_req_i ( src_req ),
.src_resp_o ( src_resp ),
.dst_clk_i,
.dst_rst_ni,
.dst_req_o ( dst_req ),
.dst_resp_i ( dst_resp )
);
endmodule
module axi_lite_cdc_intf #(
parameter int unsigned AXI_ADDR_WIDTH = 0,
parameter int unsigned AXI_DATA_WIDTH = 0,
/// Depth of the FIFO crossing the clock domain, given as 2**LOG_DEPTH.
parameter int unsigned LOG_DEPTH = 1
) (
// slave side - clocked by `src_clk_i`
input logic src_clk_i,
input logic src_rst_ni,
AXI_LITE.Slave src,
// master side - clocked by `dst_clk_i`
input logic dst_clk_i,
input logic dst_rst_ni,
AXI_LITE.Master dst
);
typedef logic [AXI_ADDR_WIDTH-1:0] addr_t;
typedef logic [AXI_DATA_WIDTH-1:0] data_t;
typedef logic [AXI_DATA_WIDTH/8-1:0] strb_t;
`AXI_LITE_TYPEDEF_AW_CHAN_T(aw_chan_t, addr_t)
`AXI_LITE_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t)
`AXI_LITE_TYPEDEF_B_CHAN_T(b_chan_t)
`AXI_LITE_TYPEDEF_AR_CHAN_T(ar_chan_t, addr_t)
`AXI_LITE_TYPEDEF_R_CHAN_T(r_chan_t, data_t)
`AXI_LITE_TYPEDEF_REQ_T(req_t, aw_chan_t, w_chan_t, ar_chan_t)
`AXI_LITE_TYPEDEF_RESP_T(resp_t, b_chan_t, r_chan_t)
req_t src_req, dst_req;
resp_t src_resp, dst_resp;
`AXI_LITE_ASSIGN_TO_REQ(src_req, src)
`AXI_LITE_ASSIGN_FROM_RESP(src, src_resp)
`AXI_LITE_ASSIGN_FROM_REQ(dst, dst_req)
`AXI_LITE_ASSIGN_TO_RESP(dst_resp, dst)
axi_cdc #(
.aw_chan_t ( aw_chan_t ),
.w_chan_t ( w_chan_t ),
.b_chan_t ( b_chan_t ),
.ar_chan_t ( ar_chan_t ),
.r_chan_t ( r_chan_t ),
.axi_req_t ( req_t ),
.axi_resp_t ( resp_t ),
.LogDepth ( LOG_DEPTH )
) i_axi_cdc (
.src_clk_i,
.src_rst_ni,
.src_req_i ( src_req ),
.src_resp_o ( src_resp ),
.dst_clk_i,
.dst_rst_ni,
.dst_req_o ( dst_req ),
.dst_resp_i ( dst_resp )
);
endmodule
// Copyright (c) 2014-2018 ETH Zurich, University of Bologna
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Authors:
// - Wolfgang Roenninger <wroennin@iis.ee.ethz.ch>
// - Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
// - Andreas Kurth <akurth@iis.ee.ethz.ch>
/// An AXI4 cut.
///
/// Breaks all combinatorial paths between its input and output.
module axi_cut #(
// bypass enable
parameter bit Bypass = 1'b0,
// AXI channel structs
parameter type aw_chan_t = logic,
parameter type w_chan_t = logic,
parameter type b_chan_t = logic,
parameter type ar_chan_t = logic,
parameter type r_chan_t = logic,
// AXI request & response structs
parameter type axi_req_t = logic,
parameter type axi_resp_t = logic
) (
input logic clk_i,
input logic rst_ni,
// salve port
input axi_req_t slv_req_i,
output axi_resp_t slv_resp_o,
// master port
output axi_req_t mst_req_o,
input axi_resp_t mst_resp_i
);
// a spill register for each channel
spill_register #(
.T ( aw_chan_t ),
.Bypass ( Bypass )
) i_reg_aw (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.valid_i ( slv_req_i.aw_valid ),
.ready_o ( slv_resp_o.aw_ready ),
.data_i ( slv_req_i.aw ),
.valid_o ( mst_req_o.aw_valid ),
.ready_i ( mst_resp_i.aw_ready ),
.data_o ( mst_req_o.aw )
);
spill_register #(
.T ( w_chan_t ),
.Bypass ( Bypass )
) i_reg_w (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.valid_i ( slv_req_i.w_valid ),
.ready_o ( slv_resp_o.w_ready ),
.data_i ( slv_req_i.w ),
.valid_o ( mst_req_o.w_valid ),
.ready_i ( mst_resp_i.w_ready ),
.data_o ( mst_req_o.w )
);
spill_register #(
.T ( b_chan_t ),
.Bypass ( Bypass )
) i_reg_b (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.valid_i ( mst_resp_i.b_valid ),
.ready_o ( mst_req_o.b_ready ),
.data_i ( mst_resp_i.b ),
.valid_o ( slv_resp_o.b_valid ),
.ready_i ( slv_req_i.b_ready ),
.data_o ( slv_resp_o.b )
);
spill_register #(
.T ( ar_chan_t ),
.Bypass ( Bypass )
) i_reg_ar (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.valid_i ( slv_req_i.ar_valid ),
.ready_o ( slv_resp_o.ar_ready ),
.data_i ( slv_req_i.ar ),
.valid_o ( mst_req_o.ar_valid ),
.ready_i ( mst_resp_i.ar_ready ),
.data_o ( mst_req_o.ar )
);
spill_register #(
.T ( r_chan_t ),
.Bypass ( Bypass )
) i_reg_r (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.valid_i ( mst_resp_i.r_valid ),
.ready_o ( mst_req_o.r_ready ),
.data_i ( mst_resp_i.r ),
.valid_o ( slv_resp_o.r_valid ),
.ready_i ( slv_req_i.r_ready ),
.data_o ( slv_resp_o.r )
);
endmodule
`include "axi/assign.svh"
`include "axi/typedef.svh"
// interface wrapper
module axi_cut_intf #(
// Bypass eneable
parameter bit BYPASS = 1'b0,
// The address width.
parameter int unsigned ADDR_WIDTH = 0,
// The data width.
parameter int unsigned DATA_WIDTH = 0,
// The ID width.
parameter int unsigned ID_WIDTH = 0,
// The user data width.
parameter int unsigned USER_WIDTH = 0
) (
input logic clk_i ,
input logic rst_ni ,
AXI_BUS.Slave in ,
AXI_BUS.Master out
);
typedef logic [ID_WIDTH-1:0] id_t;
typedef logic [ADDR_WIDTH-1:0] addr_t;
typedef logic [DATA_WIDTH-1:0] data_t;
typedef logic [DATA_WIDTH/8-1:0] strb_t;
typedef logic [USER_WIDTH-1:0] user_t;
`AXI_TYPEDEF_AW_CHAN_T(aw_chan_t, addr_t, id_t, user_t)
`AXI_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t, user_t)
`AXI_TYPEDEF_B_CHAN_T(b_chan_t, id_t, user_t)
`AXI_TYPEDEF_AR_CHAN_T(ar_chan_t, addr_t, id_t, user_t)
`AXI_TYPEDEF_R_CHAN_T(r_chan_t, data_t, id_t, user_t)
`AXI_TYPEDEF_REQ_T(axi_req_t, aw_chan_t, w_chan_t, ar_chan_t)
`AXI_TYPEDEF_RESP_T(axi_resp_t, b_chan_t, r_chan_t)
axi_req_t slv_req, mst_req;
axi_resp_t slv_resp, mst_resp;
`AXI_ASSIGN_TO_REQ(slv_req, in)
`AXI_ASSIGN_FROM_RESP(in, slv_resp)
`AXI_ASSIGN_FROM_REQ(out, mst_req)
`AXI_ASSIGN_TO_RESP(mst_resp, out)
axi_cut #(
.Bypass ( BYPASS ),
.aw_chan_t ( aw_chan_t ),
.w_chan_t ( w_chan_t ),
.b_chan_t ( b_chan_t ),
.ar_chan_t ( ar_chan_t ),
.r_chan_t ( r_chan_t ),
.axi_req_t ( axi_req_t ),
.axi_resp_t ( axi_resp_t )
) i_axi_cut (
.clk_i,
.rst_ni,
.slv_req_i ( slv_req ),
.slv_resp_o ( slv_resp ),
.mst_req_o ( mst_req ),
.mst_resp_i ( mst_resp )
);
// Check the invariants.
// pragma translate_off
`ifndef VERILATOR
initial begin
assert (ADDR_WIDTH > 0) else $fatal(1, "Wrong addr width parameter");
assert (DATA_WIDTH > 0) else $fatal(1, "Wrong data width parameter");
assert (ID_WIDTH > 0) else $fatal(1, "Wrong id width parameter");
assert (USER_WIDTH > 0) else $fatal(1, "Wrong user width parameter");
assert (in.AXI_ADDR_WIDTH == ADDR_WIDTH) else $fatal(1, "Wrong interface definition");
assert (in.AXI_DATA_WIDTH == DATA_WIDTH) else $fatal(1, "Wrong interface definition");
assert (in.AXI_ID_WIDTH == ID_WIDTH) else $fatal(1, "Wrong interface definition");
assert (in.AXI_USER_WIDTH == USER_WIDTH) else $fatal(1, "Wrong interface definition");
assert (out.AXI_ADDR_WIDTH == ADDR_WIDTH) else $fatal(1, "Wrong interface definition");
assert (out.AXI_DATA_WIDTH == DATA_WIDTH) else $fatal(1, "Wrong interface definition");
assert (out.AXI_ID_WIDTH == ID_WIDTH) else $fatal(1, "Wrong interface definition");
assert (out.AXI_USER_WIDTH == USER_WIDTH) else $fatal(1, "Wrong interface definition");
end
`endif
// pragma translate_on
endmodule
module axi_lite_cut_intf #(
// bypass enable
parameter bit BYPASS = 1'b0,
/// The address width.
parameter int unsigned ADDR_WIDTH = 0,
/// The data width.
parameter int unsigned DATA_WIDTH = 0
) (
input logic clk_i ,
input logic rst_ni ,
AXI_LITE.Slave in ,
AXI_LITE.Master out
);
typedef logic [ADDR_WIDTH-1:0] addr_t;
typedef logic [DATA_WIDTH-1:0] data_t;
typedef logic [DATA_WIDTH/8-1:0] strb_t;
`AXI_LITE_TYPEDEF_AW_CHAN_T(aw_chan_t, addr_t)
`AXI_LITE_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t)
`AXI_LITE_TYPEDEF_B_CHAN_T(b_chan_t)
`AXI_LITE_TYPEDEF_AR_CHAN_T(ar_chan_t, addr_t)
`AXI_LITE_TYPEDEF_R_CHAN_T(r_chan_t, data_t)
`AXI_LITE_TYPEDEF_REQ_T(axi_req_t, aw_chan_t, w_chan_t, ar_chan_t)
`AXI_LITE_TYPEDEF_RESP_T(axi_resp_t, b_chan_t, r_chan_t)
axi_req_t slv_req, mst_req;
axi_resp_t slv_resp, mst_resp;
`AXI_LITE_ASSIGN_TO_REQ(slv_req, in)
`AXI_LITE_ASSIGN_FROM_RESP(in, slv_resp)
`AXI_LITE_ASSIGN_FROM_REQ(out, mst_req)
`AXI_LITE_ASSIGN_TO_RESP(mst_resp, out)
axi_cut #(
.Bypass ( BYPASS ),
.aw_chan_t ( aw_chan_t ),
.w_chan_t ( w_chan_t ),
.b_chan_t ( b_chan_t ),
.ar_chan_t ( ar_chan_t ),
.r_chan_t ( r_chan_t ),
.axi_req_t ( axi_req_t ),
.axi_resp_t ( axi_resp_t )
) i_axi_cut (
.clk_i,
.rst_ni,
.slv_req_i ( slv_req ),
.slv_resp_o ( slv_resp ),
.mst_req_o ( mst_req ),
.mst_resp_i ( mst_resp )
);
// Check the invariants.
// pragma translate_off
`ifndef VERILATOR
initial begin
assert (ADDR_WIDTH > 0) else $fatal(1, "Wrong addr width parameter");
assert (DATA_WIDTH > 0) else $fatal(1, "Wrong data width parameter");
assert (in.AXI_ADDR_WIDTH == ADDR_WIDTH) else $fatal(1, "Wrong interface definition");
assert (in.AXI_DATA_WIDTH == DATA_WIDTH) else $fatal(1, "Wrong interface definition");
assert (out.AXI_ADDR_WIDTH == ADDR_WIDTH) else $fatal(1, "Wrong interface definition");
assert (out.AXI_DATA_WIDTH == DATA_WIDTH) else $fatal(1, "Wrong interface definition");
end
`endif
// pragma translate_on
endmodule
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Authors:
// - Wolfgang Roenninger <wroennin@iis.ee.ethz.ch>
// - Florian Zaruba <zarubaf@iis.ee.ethz.ch>
// - Andreas Kurth <akurth@iis.ee.ethz.ch>
/// Synthesizable module that (randomly) delays AXI channels.
module axi_delayer #(
// AXI channel types
parameter type aw_chan_t = logic,
parameter type w_chan_t = logic,
parameter type b_chan_t = logic,
parameter type ar_chan_t = logic,
parameter type r_chan_t = logic,
// AXI request & response types
parameter type axi_req_t = logic,
parameter type axi_resp_t = logic,
// delay parameters
parameter bit StallRandomInput = 0,
parameter bit StallRandomOutput = 0,
parameter int unsigned FixedDelayInput = 1,
parameter int unsigned FixedDelayOutput = 1
) (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
// slave port
input axi_req_t slv_req_i,
output axi_resp_t slv_resp_o,
// master port
output axi_req_t mst_req_o,
input axi_resp_t mst_resp_i
);
// AW
stream_delay #(
.StallRandom ( StallRandomInput ),
.FixedDelay ( FixedDelayInput ),
.payload_t ( aw_chan_t )
) i_stream_delay_aw (
.clk_i,
.rst_ni,
.payload_i ( slv_req_i.aw ),
.ready_o ( slv_resp_o.aw_ready ),
.valid_i ( slv_req_i.aw_valid ),
.payload_o ( mst_req_o.aw ),
.ready_i ( mst_resp_i.aw_ready ),
.valid_o ( mst_req_o.aw_valid )
);
// AR
stream_delay #(
.StallRandom ( StallRandomInput ),
.FixedDelay ( FixedDelayInput ),
.payload_t ( ar_chan_t )
) i_stream_delay_ar (
.clk_i,
.rst_ni,
.payload_i ( slv_req_i.ar ),
.ready_o ( slv_resp_o.ar_ready ),
.valid_i ( slv_req_i.ar_valid ),
.payload_o ( mst_req_o.ar ),
.ready_i ( mst_resp_i.ar_ready ),
.valid_o ( mst_req_o.ar_valid )
);
// W
stream_delay #(
.StallRandom ( StallRandomInput ),
.FixedDelay ( FixedDelayInput ),
.payload_t ( w_chan_t )
) i_stream_delay_w (
.clk_i,
.rst_ni,
.payload_i ( slv_req_i.w ),
.ready_o ( slv_resp_o.w_ready ),
.valid_i ( slv_req_i.w_valid ),
.payload_o ( mst_req_o.w ),
.ready_i ( mst_resp_i.w_ready ),
.valid_o ( mst_req_o.w_valid )
);
// B
stream_delay #(
.StallRandom ( StallRandomOutput ),
.FixedDelay ( FixedDelayOutput ),
.payload_t ( b_chan_t )
) i_stream_delay_b (
.clk_i,
.rst_ni,
.payload_i ( mst_resp_i.b ),
.ready_o ( mst_req_o.b_ready ),
.valid_i ( mst_resp_i.b_valid ),
.payload_o ( slv_resp_o.b ),
.ready_i ( slv_req_i.b_ready ),
.valid_o ( slv_resp_o.b_valid )
);
// R
stream_delay #(
.StallRandom ( StallRandomOutput ),
.FixedDelay ( FixedDelayOutput ),
.payload_t ( r_chan_t )
) i_stream_delay_r (
.clk_i,
.rst_ni,
.payload_i ( mst_resp_i.r ),
.ready_o ( mst_req_o.r_ready ),
.valid_i ( mst_resp_i.r_valid ),
.payload_o ( slv_resp_o.r ),
.ready_i ( slv_req_i.r_ready ),
.valid_o ( slv_resp_o.r_valid )
);
endmodule
`include "axi/typedef.svh"
`include "axi/assign.svh"
// interface wrapper
module axi_delayer_intf #(
// Synopsys DC requires a default value for parameters.
parameter int unsigned AXI_ID_WIDTH = 0,
parameter int unsigned AXI_ADDR_WIDTH = 0,
parameter int unsigned AXI_DATA_WIDTH = 0,
parameter int unsigned AXI_USER_WIDTH = 0,
parameter bit STALL_RANDOM_INPUT = 0,
parameter bit STALL_RANDOM_OUTPUT = 0,
parameter int unsigned FIXED_DELAY_INPUT = 1,
parameter int unsigned FIXED_DELAY_OUTPUT = 1
) (
input logic clk_i,
input logic rst_ni,
AXI_BUS.Slave slv,
AXI_BUS.Master mst
);
typedef logic [AXI_ID_WIDTH-1:0] id_t;
typedef logic [AXI_ADDR_WIDTH-1:0] addr_t;
typedef logic [AXI_DATA_WIDTH-1:0] data_t;
typedef logic [AXI_DATA_WIDTH/8-1:0] strb_t;
typedef logic [AXI_USER_WIDTH-1:0] user_t;
`AXI_TYPEDEF_AW_CHAN_T(aw_chan_t, addr_t, id_t, user_t)
`AXI_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t, user_t)
`AXI_TYPEDEF_B_CHAN_T(b_chan_t, id_t, user_t)
`AXI_TYPEDEF_AR_CHAN_T(ar_chan_t, addr_t, id_t, user_t)
`AXI_TYPEDEF_R_CHAN_T(r_chan_t, data_t, id_t, user_t)
`AXI_TYPEDEF_REQ_T(axi_req_t, aw_chan_t, w_chan_t, ar_chan_t)
`AXI_TYPEDEF_RESP_T(axi_resp_t, b_chan_t, r_chan_t)
axi_req_t slv_req, mst_req;
axi_resp_t slv_resp, mst_resp;
`AXI_ASSIGN_TO_REQ(slv_req, slv)
`AXI_ASSIGN_FROM_RESP(slv, slv_resp)
`AXI_ASSIGN_FROM_REQ(mst, mst_req)
`AXI_ASSIGN_TO_RESP(mst_resp, mst)
axi_delayer #(
.aw_chan_t ( aw_chan_t ),
.w_chan_t ( w_chan_t ),
.b_chan_t ( b_chan_t ),
.ar_chan_t ( ar_chan_t ),
.r_chan_t ( r_chan_t ),
.axi_req_t ( axi_req_t ),
.axi_resp_t ( axi_resp_t ),
.StallRandomInput ( STALL_RANDOM_INPUT ),
.StallRandomOutput ( STALL_RANDOM_OUTPUT ),
.FixedDelayInput ( FIXED_DELAY_INPUT ),
.FixedDelayOutput ( FIXED_DELAY_OUTPUT )
) i_axi_delayer (
.clk_i, // Clock
.rst_ni, // Asynchronous reset active low
.slv_req_i ( slv_req ),
.slv_resp_o ( slv_resp ),
.mst_req_o ( mst_req ),
.mst_resp_i ( mst_resp )
);
// pragma translate_off
`ifndef VERILATOR
initial begin: p_assertions
assert (AXI_ID_WIDTH >= 1) else $fatal(1, "AXI ID width must be at least 1!");
assert (AXI_ADDR_WIDTH >= 1) else $fatal(1, "AXI ADDR width must be at least 1!");
assert (AXI_DATA_WIDTH >= 1) else $fatal(1, "AXI DATA width must be at least 1!");
assert (AXI_USER_WIDTH >= 1) else $fatal(1, "AXI USER width must be at least 1!");
end
`endif
// pragma translate_on
endmodule
// Copyright 2020 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Authors:
// - Matheus Cavalcante <matheusd@iis.ee.ethz.ch>
// NOTE: The upsizer does not support WRAP bursts, and will answer with SLVERR
// upon receiving a burst of such type. In addition to that, the downsizer also
// does not support FIXED bursts with incoming axlen != 0.
module axi_dw_converter #(
parameter int unsigned AxiMaxReads = 1 , // Number of outstanding reads
parameter int unsigned AxiSlvPortDataWidth = 8 , // Data width of the slv port
parameter int unsigned AxiMstPortDataWidth = 8 , // Data width of the mst port
parameter int unsigned AxiAddrWidth = 1 , // Address width
parameter int unsigned AxiIdWidth = 1 , // ID width
parameter type aw_chan_t = logic, // AW Channel Type
parameter type mst_w_chan_t = logic, // W Channel Type for the mst port
parameter type slv_w_chan_t = logic, // W Channel Type for the slv port
parameter type b_chan_t = logic, // B Channel Type
parameter type ar_chan_t = logic, // AR Channel Type
parameter type mst_r_chan_t = logic, // R Channel Type for the mst port
parameter type slv_r_chan_t = logic, // R Channel Type for the slv port
parameter type axi_mst_req_t = logic, // AXI Request Type for mst ports
parameter type axi_mst_resp_t = logic, // AXI Response Type for mst ports
parameter type axi_slv_req_t = logic, // AXI Request Type for slv ports
parameter type axi_slv_resp_t = logic // AXI Response Type for slv ports
) (
input logic clk_i,
input logic rst_ni,
// Slave interface
input axi_slv_req_t slv_req_i,
output axi_slv_resp_t slv_resp_o,
// Master interface
output axi_mst_req_t mst_req_o,
input axi_mst_resp_t mst_resp_i
);
if (AxiMstPortDataWidth == AxiSlvPortDataWidth) begin: gen_no_dw_conversion
assign mst_req_o = slv_req_i ;
assign slv_resp_o = mst_resp_i;
end : gen_no_dw_conversion
if (AxiMstPortDataWidth > AxiSlvPortDataWidth) begin: gen_dw_upsize
axi_dw_upsizer #(
.AxiMaxReads (AxiMaxReads ),
.AxiSlvPortDataWidth(AxiSlvPortDataWidth),
.AxiMstPortDataWidth(AxiMstPortDataWidth),
.AxiAddrWidth (AxiAddrWidth ),
.AxiIdWidth (AxiIdWidth ),
.aw_chan_t (aw_chan_t ),
.mst_w_chan_t (mst_w_chan_t ),
.slv_w_chan_t (slv_w_chan_t ),
.b_chan_t (b_chan_t ),
.ar_chan_t (ar_chan_t ),
.mst_r_chan_t (mst_r_chan_t ),
.slv_r_chan_t (slv_r_chan_t ),
.axi_mst_req_t (axi_mst_req_t ),
.axi_mst_resp_t (axi_mst_resp_t ),
.axi_slv_req_t (axi_slv_req_t ),
.axi_slv_resp_t (axi_slv_resp_t )
) i_axi_dw_upsizer (
.clk_i (clk_i ),
.rst_ni (rst_ni ),
// Slave interface
.slv_req_i (slv_req_i ),
.slv_resp_o(slv_resp_o),
// Master interface
.mst_req_o (mst_req_o ),
.mst_resp_i(mst_resp_i)
);
end : gen_dw_upsize
if (AxiMstPortDataWidth < AxiSlvPortDataWidth) begin: gen_dw_downsize
axi_dw_downsizer #(
.AxiMaxReads (AxiMaxReads ),
.AxiSlvPortDataWidth(AxiSlvPortDataWidth),
.AxiMstPortDataWidth(AxiMstPortDataWidth),
.AxiAddrWidth (AxiAddrWidth ),
.AxiIdWidth (AxiIdWidth ),
.aw_chan_t (aw_chan_t ),
.mst_w_chan_t (mst_w_chan_t ),
.slv_w_chan_t (slv_w_chan_t ),
.b_chan_t (b_chan_t ),
.ar_chan_t (ar_chan_t ),
.mst_r_chan_t (mst_r_chan_t ),
.slv_r_chan_t (slv_r_chan_t ),
.axi_mst_req_t (axi_mst_req_t ),
.axi_mst_resp_t (axi_mst_resp_t ),
.axi_slv_req_t (axi_slv_req_t ),
.axi_slv_resp_t (axi_slv_resp_t )
) i_axi_dw_downsizer (
.clk_i (clk_i ),
.rst_ni (rst_ni ),
// Slave interface
.slv_req_i (slv_req_i ),
.slv_resp_o(slv_resp_o),
// Master interface
.mst_req_o (mst_req_o ),
.mst_resp_i(mst_resp_i)
);
end : gen_dw_downsize
endmodule : axi_dw_converter
// Interface wrapper
`include "axi/assign.svh"
`include "axi/typedef.svh"
module axi_dw_converter_intf #(
parameter int unsigned AXI_ID_WIDTH = 1,
parameter int unsigned AXI_ADDR_WIDTH = 1,
parameter int unsigned AXI_SLV_PORT_DATA_WIDTH = 8,
parameter int unsigned AXI_MST_PORT_DATA_WIDTH = 8,
parameter int unsigned AXI_USER_WIDTH = 0,
parameter int unsigned AXI_MAX_READS = 8
) (
input logic clk_i,
input logic rst_ni,
AXI_BUS.Slave slv,
AXI_BUS.Master mst
);
typedef logic [AXI_ID_WIDTH-1:0] id_t ;
typedef logic [AXI_ADDR_WIDTH-1:0] addr_t ;
typedef logic [AXI_MST_PORT_DATA_WIDTH-1:0] mst_data_t ;
typedef logic [AXI_MST_PORT_DATA_WIDTH/8-1:0] mst_strb_t;
typedef logic [AXI_SLV_PORT_DATA_WIDTH-1:0] slv_data_t ;
typedef logic [AXI_SLV_PORT_DATA_WIDTH/8-1:0] slv_strb_t;
typedef logic [AXI_USER_WIDTH-1:0] user_t ;
`AXI_TYPEDEF_AW_CHAN_T(aw_chan_t, addr_t, id_t, user_t)
`AXI_TYPEDEF_W_CHAN_T(mst_w_chan_t, mst_data_t, mst_strb_t, user_t)
`AXI_TYPEDEF_W_CHAN_T(slv_w_chan_t, slv_data_t, slv_strb_t, user_t)
`AXI_TYPEDEF_B_CHAN_T(b_chan_t, id_t, user_t)
`AXI_TYPEDEF_AR_CHAN_T(ar_chan_t, addr_t, id_t, user_t)
`AXI_TYPEDEF_R_CHAN_T(mst_r_chan_t, mst_data_t, id_t, user_t)
`AXI_TYPEDEF_R_CHAN_T(slv_r_chan_t, slv_data_t, id_t, user_t)
`AXI_TYPEDEF_REQ_T(mst_req_t, aw_chan_t, mst_w_chan_t, ar_chan_t)
`AXI_TYPEDEF_RESP_T(mst_resp_t, b_chan_t, mst_r_chan_t)
`AXI_TYPEDEF_REQ_T(slv_req_t, aw_chan_t, slv_w_chan_t, ar_chan_t)
`AXI_TYPEDEF_RESP_T(slv_resp_t, b_chan_t, slv_r_chan_t)
slv_req_t slv_req;
slv_resp_t slv_resp;
mst_req_t mst_req;
mst_resp_t mst_resp;
`AXI_ASSIGN_TO_REQ(slv_req, slv)
`AXI_ASSIGN_FROM_RESP(slv, slv_resp)
`AXI_ASSIGN_FROM_REQ(mst, mst_req)
`AXI_ASSIGN_TO_RESP(mst_resp, mst)
axi_dw_converter #(
.AxiMaxReads ( AXI_MAX_READS ),
.AxiSlvPortDataWidth( AXI_SLV_PORT_DATA_WIDTH ),
.AxiMstPortDataWidth( AXI_MST_PORT_DATA_WIDTH ),
.AxiAddrWidth ( AXI_ADDR_WIDTH ),
.AxiIdWidth ( AXI_ID_WIDTH ),
.aw_chan_t ( aw_chan_t ),
.mst_w_chan_t ( mst_w_chan_t ),
.slv_w_chan_t ( slv_w_chan_t ),
.b_chan_t ( b_chan_t ),
.ar_chan_t ( ar_chan_t ),
.mst_r_chan_t ( mst_r_chan_t ),
.slv_r_chan_t ( slv_r_chan_t ),
.axi_mst_req_t ( mst_req_t ),
.axi_mst_resp_t ( mst_resp_t ),
.axi_slv_req_t ( slv_req_t ),
.axi_slv_resp_t ( slv_resp_t )
) i_axi_dw_converter (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
// slave port
.slv_req_i ( slv_req ),
.slv_resp_o ( slv_resp ),
// master port
.mst_req_o ( mst_req ),
.mst_resp_i ( mst_resp )
);
endmodule : axi_dw_converter_intf
// Copyright 2019 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Authors:
// - Wolfgang Roenninger <wroennin@iis.ee.ethz.ch>
// - Andreas Kurth <akurth@iis.ee.ethz.ch>
// - Matheus Cavalcante <matheusd@iis.ee.ethz.ch>
// AXI Error Slave: This module always responds with an AXI error for transactions that are sent to
// it. This module optionally supports ATOPs if the `ATOPs` parameter is set.
module axi_err_slv #(
parameter int unsigned AxiIdWidth = 0, // AXI ID Width
parameter type axi_req_t = logic, // AXI 4 request struct, with atop field
parameter type axi_resp_t = logic, // AXI 4 response struct
parameter axi_pkg::resp_t Resp = axi_pkg::RESP_DECERR, // Error generated by this slave.
parameter int unsigned RespWidth = 32'd64, // Data response width, gets zero extended or truncated to r.data.
parameter logic [RespWidth-1:0] RespData = 64'hCA11AB1EBADCAB1E, // Hexvalue for data return value
parameter bit ATOPs = 1'b1, // Activate support for ATOPs. Set to 1 if this slave could ever get an atomic AXI transaction.
parameter int unsigned MaxTrans = 1 // Maximum # of accepted transactions before stalling
) (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic test_i, // Testmode enable
// slave port
input axi_req_t slv_req_i,
output axi_resp_t slv_resp_o
);
typedef logic [AxiIdWidth-1:0] id_t;
typedef struct packed {
id_t id;
axi_pkg::len_t len;
} r_data_t;
axi_req_t err_req;
axi_resp_t err_resp;
if (ATOPs) begin
axi_atop_filter #(
.AxiIdWidth ( AxiIdWidth ),
.AxiMaxWriteTxns ( MaxTrans ),
.axi_req_t ( axi_req_t ),
.axi_resp_t ( axi_resp_t )
) i_atop_filter (
.clk_i,
.rst_ni,
.slv_req_i ( slv_req_i ),
.slv_resp_o ( slv_resp_o ),
.mst_req_o ( err_req ),
.mst_resp_i ( err_resp )
);
end else begin
assign err_req = slv_req_i;
assign slv_resp_o = err_resp;
end
// w fifo
logic w_fifo_full, w_fifo_empty;
logic w_fifo_push, w_fifo_pop;
id_t w_fifo_data;
// b fifo
logic b_fifo_full, b_fifo_empty;
logic b_fifo_push, b_fifo_pop;
id_t b_fifo_data;
// r fifo
r_data_t r_fifo_inp;
logic r_fifo_full, r_fifo_empty;
logic r_fifo_push, r_fifo_pop;
r_data_t r_fifo_data;
// r counter
logic r_cnt_clear, r_cnt_en, r_cnt_load;
axi_pkg::len_t r_current_beat;
// r status
logic r_busy_d, r_busy_q, r_busy_load;
//--------------------------------------
// Write Transactions
//--------------------------------------
// push, when there is room in the fifo
assign w_fifo_push = err_req.aw_valid & ~w_fifo_full;
assign err_resp.aw_ready = ~w_fifo_full;
fifo_v3 #(
.FALL_THROUGH ( 1'b1 ),
.DEPTH ( MaxTrans ),
.dtype ( id_t )
) i_w_fifo (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.flush_i ( 1'b0 ),
.testmode_i ( test_i ),
.full_o ( w_fifo_full ),
.empty_o ( w_fifo_empty ),
.usage_o ( ),
.data_i ( err_req.aw.id ),
.push_i ( w_fifo_push ),
.data_o ( w_fifo_data ),
.pop_i ( w_fifo_pop )
);
always_comb begin : proc_w_channel
err_resp.w_ready = 1'b0;
w_fifo_pop = 1'b0;
b_fifo_push = 1'b0;
if (!w_fifo_empty && !b_fifo_full) begin
// eat the beats
err_resp.w_ready = 1'b1;
// on the last w transaction
if (err_req.w_valid && err_req.w.last) begin
w_fifo_pop = 1'b1;
b_fifo_push = 1'b1;
end
end
end
fifo_v3 #(
.FALL_THROUGH ( 1'b0 ),
.DEPTH ( unsigned'(2) ), // two placed so that w can eat beats if b is not sent
.dtype ( id_t )
) i_b_fifo (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.flush_i ( 1'b0 ),
.testmode_i ( test_i ),
.full_o ( b_fifo_full ),
.empty_o ( b_fifo_empty ),
.usage_o ( ),
.data_i ( w_fifo_data ),
.push_i ( b_fifo_push ),
.data_o ( b_fifo_data ),
.pop_i ( b_fifo_pop )
);
always_comb begin : proc_b_channel
b_fifo_pop = 1'b0;
err_resp.b = '0;
err_resp.b.id = b_fifo_data;
err_resp.b.resp = Resp;
err_resp.b_valid = 1'b0;
if (!b_fifo_empty) begin
err_resp.b_valid = 1'b1;
// b transaction
b_fifo_pop = err_req.b_ready;
end
end
//--------------------------------------
// Read Transactions
//--------------------------------------
// push if there is room in the fifo
assign r_fifo_push = err_req.ar_valid & ~r_fifo_full;
assign err_resp.ar_ready = ~r_fifo_full;
// fifo data assignment
assign r_fifo_inp.id = err_req.ar.id;
assign r_fifo_inp.len = err_req.ar.len;
fifo_v3 #(
.FALL_THROUGH ( 1'b0 ),
.DEPTH ( MaxTrans ),
.dtype ( r_data_t )
) i_r_fifo (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.flush_i ( 1'b0 ),
.testmode_i( test_i ),
.full_o ( r_fifo_full ),
.empty_o ( r_fifo_empty ),
.usage_o ( ),
.data_i ( r_fifo_inp ),
.push_i ( r_fifo_push ),
.data_o ( r_fifo_data ),
.pop_i ( r_fifo_pop )
);
always_comb begin : proc_r_channel
// default assignments
r_busy_d = r_busy_q;
r_busy_load = 1'b0;
// r fifo signals
r_fifo_pop = 1'b0;
// r counter signals
r_cnt_clear = 1'b0;
r_cnt_en = 1'b0;
r_cnt_load = 1'b0;
// r_channel
err_resp.r = '0;
err_resp.r.id = r_fifo_data.id;
err_resp.r.data = RespData;
err_resp.r.resp = Resp;
err_resp.r_valid = 1'b0;
// control
if (r_busy_q) begin
err_resp.r_valid = 1'b1;
err_resp.r.last = (r_current_beat == '0);
// r transaction
if (err_req.r_ready) begin
r_cnt_en = 1'b1;
if (r_current_beat == '0) begin
r_busy_d = 1'b0;
r_busy_load = 1'b1;
r_cnt_clear = 1'b1;
r_fifo_pop = 1'b1;
end
end
end else begin
// when not busy and fifo not empty, start counter err gen
if (!r_fifo_empty) begin
r_busy_d = 1'b1;
r_busy_load = 1'b1;
r_cnt_load = 1'b1;
end
end
end
always_ff @(posedge clk_i, negedge rst_ni) begin
if (!rst_ni) begin
r_busy_q <= '0;
end else if (r_busy_load) begin
r_busy_q <= r_busy_d;
end
end
counter #(
.WIDTH ($bits(axi_pkg::len_t))
) i_r_counter (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.clear_i ( r_cnt_clear ),
.en_i ( r_cnt_en ),
.load_i ( r_cnt_load ),
.down_i ( 1'b1 ),
.d_i ( r_fifo_data.len ),
.q_o ( r_current_beat ),
.overflow_o( )
);
// pragma translate_off
`ifndef VERILATOR
`ifndef XSIM
initial begin
assert (Resp == axi_pkg::RESP_DECERR || Resp == axi_pkg::RESP_SLVERR) else
$fatal(1, "This module may only generate RESP_DECERR or RESP_SLVERR responses!");
end
default disable iff (!rst_ni);
if (!ATOPs) begin : gen_assert_atops_unsupported
assume property( @(posedge clk_i) (slv_req_i.aw_valid |-> slv_req_i.aw.atop == '0)) else
$fatal(1, "Got ATOP but not configured to support ATOPs!");
end
`endif
`endif
// pragma translate_on
endmodule
// Copyright 2019 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Authors:
// - Wolfgang Roenninger <wroennin@iis.ee.ethz.ch>
// - Andreas Kurth <akurth@iis.ee.ethz.ch>
// AXI ID Prepend: This module prepends/strips the MSB from the AXI IDs.
// Constraints enforced through assertions: ID width of slave and master port
module axi_id_prepend #(
parameter int unsigned NoBus = 1, // Can take multiple axi busses
parameter int unsigned AxiIdWidthSlvPort = 4, // AXI ID Width of the Slave Ports
parameter int unsigned AxiIdWidthMstPort = 6, // AXI ID Width of the Master Ports
parameter type slv_aw_chan_t = logic, // AW Channel Type for slv port
parameter type slv_w_chan_t = logic, // W Channel Type for slv port
parameter type slv_b_chan_t = logic, // B Channel Type for slv port
parameter type slv_ar_chan_t = logic, // AR Channel Type for slv port
parameter type slv_r_chan_t = logic, // R Channel Type for slv port
parameter type mst_aw_chan_t = logic, // AW Channel Type for mst port
parameter type mst_w_chan_t = logic, // W Channel Type for mst port
parameter type mst_b_chan_t = logic, // B Channel Type for mst port
parameter type mst_ar_chan_t = logic, // AR Channel Type for mst port
parameter type mst_r_chan_t = logic, // R Channel Type for mst port
// DEPENDENT PARAMETER DO NOT OVERWRITE!
parameter int unsigned PreIdWidth = AxiIdWidthMstPort - AxiIdWidthSlvPort
) (
input logic [PreIdWidth-1:0] pre_id_i, // ID to be prepended
// slave port (input), connect master modules here
// AW channel
input slv_aw_chan_t [NoBus-1:0] slv_aw_chans_i,
input logic [NoBus-1:0] slv_aw_valids_i,
output logic [NoBus-1:0] slv_aw_readies_o,
// W channel
input slv_w_chan_t [NoBus-1:0] slv_w_chans_i,
input logic [NoBus-1:0] slv_w_valids_i,
output logic [NoBus-1:0] slv_w_readies_o,
// B channel
output slv_b_chan_t [NoBus-1:0] slv_b_chans_o,
output logic [NoBus-1:0] slv_b_valids_o,
input logic [NoBus-1:0] slv_b_readies_i,
// AR channel
input slv_ar_chan_t [NoBus-1:0] slv_ar_chans_i,
input logic [NoBus-1:0] slv_ar_valids_i,
output logic [NoBus-1:0] slv_ar_readies_o,
// R channel
output slv_r_chan_t [NoBus-1:0] slv_r_chans_o,
output logic [NoBus-1:0] slv_r_valids_o,
input logic [NoBus-1:0] slv_r_readies_i,
// master ports (output), connect slave modules here
// AW channel
output mst_aw_chan_t [NoBus-1:0] mst_aw_chans_o,
output logic [NoBus-1:0] mst_aw_valids_o,
input logic [NoBus-1:0] mst_aw_readies_i,
// W channel
output mst_w_chan_t [NoBus-1:0] mst_w_chans_o,
output logic [NoBus-1:0] mst_w_valids_o,
input logic [NoBus-1:0] mst_w_readies_i,
// B channel
input mst_b_chan_t [NoBus-1:0] mst_b_chans_i,
input logic [NoBus-1:0] mst_b_valids_i,
output logic [NoBus-1:0] mst_b_readies_o,
// AR channel
output mst_ar_chan_t [NoBus-1:0] mst_ar_chans_o,
output logic [NoBus-1:0] mst_ar_valids_o,
input logic [NoBus-1:0] mst_ar_readies_i,
// R channel
input mst_r_chan_t [NoBus-1:0] mst_r_chans_i,
input logic [NoBus-1:0] mst_r_valids_i,
output logic [NoBus-1:0] mst_r_readies_o
);
// prepend the ID
for (genvar i = 0; i < NoBus; i++) begin : gen_id_prepend
if (PreIdWidth == 0) begin : gen_no_prepend
assign mst_aw_chans_o[i] = slv_aw_chans_i[i];
assign mst_ar_chans_o[i] = slv_ar_chans_i[i];
end else begin : gen_prepend
always_comb begin
mst_aw_chans_o[i] = slv_aw_chans_i[i];
mst_ar_chans_o[i] = slv_ar_chans_i[i];
mst_aw_chans_o[i].id = {pre_id_i, slv_aw_chans_i[i].id[AxiIdWidthSlvPort-1:0]};
mst_ar_chans_o[i].id = {pre_id_i, slv_ar_chans_i[i].id[AxiIdWidthSlvPort-1:0]};
end
end
// The ID is in the highest bits of the struct, so an assignment from a channel with a wide ID
// to a channel with a shorter ID correctly cuts the prepended ID.
assign slv_b_chans_o[i] = mst_b_chans_i[i];
assign slv_r_chans_o[i] = mst_r_chans_i[i];
end
// assign the handshaking's and w channel
assign mst_w_chans_o = slv_w_chans_i;
assign mst_aw_valids_o = slv_aw_valids_i;
assign slv_aw_readies_o = mst_aw_readies_i;
assign mst_w_valids_o = slv_w_valids_i;
assign slv_w_readies_o = mst_w_readies_i;
assign slv_b_valids_o = mst_b_valids_i;
assign mst_b_readies_o = slv_b_readies_i;
assign mst_ar_valids_o = slv_ar_valids_i;
assign slv_ar_readies_o = mst_ar_readies_i;
assign slv_r_valids_o = mst_r_valids_i;
assign mst_r_readies_o = slv_r_readies_i;
// pragma translate_off
`ifndef VERILATOR
initial begin : p_assert
assert(NoBus > 0)
else $fatal(1, "Input must be at least one element wide.");
assert(PreIdWidth == ($bits(mst_aw_chans_o[0].id) - $bits(slv_aw_chans_i[0].id)))
else $fatal(1, "Prepend ID Width must be: $bits(mst_aw_chans_o.id)-$bits(slv_aw_chans_i.id)");
assert ($bits(mst_aw_chans_o[0].id) > $bits(slv_aw_chans_i[0].id))
else $fatal(1, "The master AXI port has to have a wider ID than the slave port.");
end
aw_id : assert final(
mst_aw_chans_o[0].id[$bits(slv_aw_chans_i[0].id)-1:0] === slv_aw_chans_i[0].id)
else $fatal (1, "Something with the AW channel ID prepending went wrong.");
aw_addr : assert final(mst_aw_chans_o[0].addr === slv_aw_chans_i[0].addr)
else $fatal (1, "Something with the AW channel ID prepending went wrong.");
aw_len : assert final(mst_aw_chans_o[0].len === slv_aw_chans_i[0].len)
else $fatal (1, "Something with the AW channel ID prepending went wrong.");
aw_size : assert final(mst_aw_chans_o[0].size === slv_aw_chans_i[0].size)
else $fatal (1, "Something with the AW channel ID prepending went wrong.");
aw_qos : assert final(mst_aw_chans_o[0].qos === slv_aw_chans_i[0].qos)
else $fatal (1, "Something with the AW channel ID prepending went wrong.");
b_id : assert final(
mst_b_chans_i[0].id[$bits(slv_b_chans_o[0].id)-1:0] === slv_b_chans_o[0].id)
else $fatal (1, "Something with the B channel ID stripping went wrong.");
b_resp : assert final(mst_b_chans_i[0].resp === slv_b_chans_o[0].resp)
else $fatal (1, "Something with the B channel ID stripping went wrong.");
ar_id : assert final(
mst_ar_chans_o[0].id[$bits(slv_ar_chans_i[0].id)-1:0] === slv_ar_chans_i[0].id)
else $fatal (1, "Something with the AR channel ID prepending went wrong.");
ar_addr : assert final(mst_ar_chans_o[0].addr === slv_ar_chans_i[0].addr)
else $fatal (1, "Something with the AR channel ID prepending went wrong.");
ar_len : assert final(mst_ar_chans_o[0].len === slv_ar_chans_i[0].len)
else $fatal (1, "Something with the AR channel ID prepending went wrong.");
ar_size : assert final(mst_ar_chans_o[0].size === slv_ar_chans_i[0].size)
else $fatal (1, "Something with the AR channel ID prepending went wrong.");
ar_qos : assert final(mst_ar_chans_o[0].qos === slv_ar_chans_i[0].qos)
else $fatal (1, "Something with the AR channel ID prepending went wrong.");
r_id : assert final(mst_r_chans_i[0].id[$bits(slv_r_chans_o[0].id)-1:0] === slv_r_chans_o[0].id)
else $fatal (1, "Something with the R channel ID stripping went wrong.");
r_data : assert final(mst_r_chans_i[0].data === slv_r_chans_o[0].data)
else $fatal (1, "Something with the R channel ID stripping went wrong.");
r_resp : assert final(mst_r_chans_i[0].resp === slv_r_chans_o[0].resp)
else $fatal (1, "Something with the R channel ID stripping went wrong.");
`endif
// pragma translate_on
endmodule
// Copyright (c) 2014-2018 ETH Zurich, University of Bologna
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Authors:
// - Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
// - Andreas Kurth <akurth@iis.ee.ethz.ch>
`include "axi/assign.svh"
/// A connector that joins two AXI interfaces.
module axi_join_intf (
AXI_BUS.Slave in,
AXI_BUS.Master out
);
`AXI_ASSIGN(out, in)
// pragma translate_off
`ifndef VERILATOR
initial begin
assert(in.AXI_ADDR_WIDTH == out.AXI_ADDR_WIDTH);
assert(in.AXI_DATA_WIDTH == out.AXI_DATA_WIDTH);
assert(in.AXI_ID_WIDTH <= out.AXI_ID_WIDTH );
assert(in.AXI_USER_WIDTH == out.AXI_USER_WIDTH);
end
`endif
// pragma translate_on
endmodule
// Copyright (c) 2014-2018 ETH Zurich, University of Bologna
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Authors:
// - Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
// - Andreas Kurth <akurth@iis.ee.ethz.ch>
`include "axi/assign.svh"
/// A connector that joins two AXI-Lite interfaces.
module axi_lite_join_intf (
AXI_LITE.Slave in,
AXI_LITE.Master out
);
`AXI_LITE_ASSIGN(out, in)
// pragma translate_off
`ifndef VERILATOR
initial begin
assert(in.AXI_ADDR_WIDTH == out.AXI_ADDR_WIDTH);
assert(in.AXI_DATA_WIDTH == out.AXI_DATA_WIDTH);
end
`endif
// pragma translate_on
endmodule
// Copyright (c) 2014-2018 ETH Zurich, University of Bologna
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Authors:
// - Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
// - Wolfgang Roenninger <wroennin@iis.ee.ethz.ch>
// - Andreas Kurth <akurth@iis.ee.ethz.ch>
/// An AXI4-Lite to AXI4 adapter.
module axi_lite_to_axi #(
parameter int unsigned AxiDataWidth = 32'd0,
// LITE AXI structs
parameter type req_lite_t = logic,
parameter type resp_lite_t = logic,
// FULL AXI structs
parameter type axi_req_t = logic,
parameter type axi_resp_t = logic
) (
// Slave AXI LITE port
input req_lite_t slv_req_lite_i,
output resp_lite_t slv_resp_lite_o,
input axi_pkg::cache_t slv_aw_cache_i,
input axi_pkg::cache_t slv_ar_cache_i,
// Master AXI port
output axi_req_t mst_req_o,
input axi_resp_t mst_resp_i
);
localparam int unsigned AxiSize = axi_pkg::size_t'($unsigned($clog2(AxiDataWidth/8)));
// request assign
assign mst_req_o = '{
aw: '{
addr: slv_req_lite_i.aw.addr,
prot: slv_req_lite_i.aw.prot,
size: AxiSize,
burst: axi_pkg::BURST_FIXED,
cache: slv_aw_cache_i,
default: '0
},
aw_valid: slv_req_lite_i.aw_valid,
w: '{
data: slv_req_lite_i.w.data,
strb: slv_req_lite_i.w.strb,
last: 1'b1,
default: '0
},
w_valid: slv_req_lite_i.w_valid,
b_ready: slv_req_lite_i.b_ready,
ar: '{
addr: slv_req_lite_i.ar.addr,
prot: slv_req_lite_i.ar.prot,
size: AxiSize,
burst: axi_pkg::BURST_FIXED,
cache: slv_ar_cache_i,
default: '0
},
ar_valid: slv_req_lite_i.ar_valid,
r_ready: slv_req_lite_i.r_ready,
default: '0
};
// response assign
assign slv_resp_lite_o = '{
aw_ready: mst_resp_i.aw_ready,
w_ready: mst_resp_i.w_ready,
b: '{
resp: mst_resp_i.b.resp,
default: '0
},
b_valid: mst_resp_i.b_valid,
ar_ready: mst_resp_i.ar_ready,
r: '{
data: mst_resp_i.r.data,
resp: mst_resp_i.r.resp,
default: '0
},
r_valid: mst_resp_i.r_valid,
default: '0
};
// pragma translate_off
`ifndef VERILATOR
initial begin
assert (AxiDataWidth > 0) else $fatal(1, "Data width must be non-zero!");
end
`endif
// pragma translate_on
endmodule
module axi_lite_to_axi_intf #(
parameter int unsigned AXI_DATA_WIDTH = 32'd0
) (
AXI_LITE.Slave in,
input axi_pkg::cache_t slv_aw_cache_i,
input axi_pkg::cache_t slv_ar_cache_i,
AXI_BUS.Master out
);
localparam int unsigned AxiSize = axi_pkg::size_t'($unsigned($clog2(AXI_DATA_WIDTH/8)));
// pragma translate_off
initial begin
assert(in.AXI_ADDR_WIDTH == out.AXI_ADDR_WIDTH);
assert(in.AXI_DATA_WIDTH == out.AXI_DATA_WIDTH);
assert(AXI_DATA_WIDTH == out.AXI_DATA_WIDTH);
end
// pragma translate_on
assign out.aw_id = '0;
assign out.aw_addr = in.aw_addr;
assign out.aw_len = '0;
assign out.aw_size = AxiSize;
assign out.aw_burst = axi_pkg::BURST_FIXED;
assign out.aw_lock = '0;
assign out.aw_cache = slv_aw_cache_i;
assign out.aw_prot = '0;
assign out.aw_qos = '0;
assign out.aw_region = '0;
assign out.aw_atop = '0;
assign out.aw_user = '0;
assign out.aw_valid = in.aw_valid;
assign in.aw_ready = out.aw_ready;
assign out.w_data = in.w_data;
assign out.w_strb = in.w_strb;
assign out.w_last = '1;
assign out.w_user = '0;
assign out.w_valid = in.w_valid;
assign in.w_ready = out.w_ready;
assign in.b_resp = out.b_resp;
assign in.b_valid = out.b_valid;
assign out.b_ready = in.b_ready;
assign out.ar_id = '0;
assign out.ar_addr = in.ar_addr;
assign out.ar_len = '0;
assign out.ar_size = AxiSize;
assign out.ar_burst = axi_pkg::BURST_FIXED;
assign out.ar_lock = '0;
assign out.ar_cache = slv_ar_cache_i;
assign out.ar_prot = '0;
assign out.ar_qos = '0;
assign out.ar_region = '0;
assign out.ar_user = '0;
assign out.ar_valid = in.ar_valid;
assign in.ar_ready = out.ar_ready;
assign in.r_data = out.r_data;
assign in.r_resp = out.r_resp;
assign in.r_valid = out.r_valid;
assign out.r_ready = in.r_ready;
endmodule
// Copyright (c) 2014-2018 ETH Zurich, University of Bologna
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Authors:
// - Andreas Kurth <akurth@iis.ee.ethz.ch>
// - Wolfgang Roenninger <wroennin@iis.ee.ethz.ch>
// - Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
/// Modify addresses on an AXI4 bus
module axi_modify_address #(
/// Request type of the slave port
parameter type slv_req_t = logic,
/// Address type of the master port
parameter type mst_addr_t = logic,
/// Request type of the master port
parameter type mst_req_t = logic,
/// Response type of slave and master port
parameter type axi_resp_t = logic
) (
/// Slave port request
input slv_req_t slv_req_i,
/// Slave port response
output axi_resp_t slv_resp_o,
/// AW address on master port; must remain stable while an AW handshake is pending.
input mst_addr_t mst_aw_addr_i,
/// AR address on master port; must remain stable while an AR handshake is pending.
input mst_addr_t mst_ar_addr_i,
/// Master port request
output mst_req_t mst_req_o,
/// Master port response
input axi_resp_t mst_resp_i
);
assign mst_req_o = '{
aw: '{
id: slv_req_i.aw.id,
addr: mst_aw_addr_i,
len: slv_req_i.aw.len,
size: slv_req_i.aw.size,
burst: slv_req_i.aw.burst,
lock: slv_req_i.aw.lock,
cache: slv_req_i.aw.cache,
prot: slv_req_i.aw.prot,
qos: slv_req_i.aw.qos,
region: slv_req_i.aw.region,
atop: slv_req_i.aw.atop,
user: slv_req_i.aw.user,
default: '0
},
aw_valid: slv_req_i.aw_valid,
w: slv_req_i.w,
w_valid: slv_req_i.w_valid,
b_ready: slv_req_i.b_ready,
ar: '{
id: slv_req_i.ar.id,
addr: mst_ar_addr_i,
len: slv_req_i.ar.len,
size: slv_req_i.ar.size,
burst: slv_req_i.ar.burst,
lock: slv_req_i.ar.lock,
cache: slv_req_i.ar.cache,
prot: slv_req_i.ar.prot,
qos: slv_req_i.ar.qos,
region: slv_req_i.ar.region,
user: slv_req_i.ar.user,
default: '0
},
ar_valid: slv_req_i.ar_valid,
r_ready: slv_req_i.r_ready,
default: '0
};
assign slv_resp_o = mst_resp_i;
endmodule
`include "axi/typedef.svh"
`include "axi/assign.svh"
/// Interface variant of [`axi_modify_address`](module.axi_modify_address)
module axi_modify_address_intf #(
/// Address width of slave port
parameter int unsigned AXI_SLV_PORT_ADDR_WIDTH = 0,
/// Address width of master port
parameter int unsigned AXI_MST_PORT_ADDR_WIDTH = AXI_SLV_PORT_ADDR_WIDTH,
/// Data width of slave and master port
parameter int unsigned AXI_DATA_WIDTH = 0,
/// ID width of slave and master port
parameter int unsigned AXI_ID_WIDTH = 0,
/// User signal width of slave and master port
parameter int unsigned AXI_USER_WIDTH = 0,
/// Derived (=DO NOT OVERRIDE) type of master port addresses
type mst_addr_t = logic [AXI_MST_PORT_ADDR_WIDTH-1:0]
) (
/// Slave port
AXI_BUS.Slave slv,
/// AW address on master port; must remain stable while an AW handshake is pending.
input mst_addr_t mst_aw_addr_i,
/// AR address on master port; must remain stable while an AR handshake is pending.
input mst_addr_t mst_ar_addr_i,
/// Master port
AXI_BUS.Master mst
);
typedef logic [AXI_ID_WIDTH-1:0] id_t;
typedef logic [AXI_SLV_PORT_ADDR_WIDTH-1:0] slv_addr_t;
typedef logic [AXI_DATA_WIDTH-1:0] data_t;
typedef logic [AXI_DATA_WIDTH/8-1:0] strb_t;
typedef logic [AXI_USER_WIDTH-1:0] user_t;
`AXI_TYPEDEF_AW_CHAN_T(slv_aw_chan_t, slv_addr_t, id_t, user_t)
`AXI_TYPEDEF_AW_CHAN_T(mst_aw_chan_t, mst_addr_t, id_t, user_t)
`AXI_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t, user_t)
`AXI_TYPEDEF_B_CHAN_T(b_chan_t, id_t, user_t)
`AXI_TYPEDEF_AR_CHAN_T(slv_ar_chan_t, slv_addr_t, id_t, user_t)
`AXI_TYPEDEF_AR_CHAN_T(mst_ar_chan_t, mst_addr_t, id_t, user_t)
`AXI_TYPEDEF_R_CHAN_T(r_chan_t, data_t, id_t, user_t)
`AXI_TYPEDEF_REQ_T(slv_req_t, slv_aw_chan_t, w_chan_t, slv_ar_chan_t)
`AXI_TYPEDEF_REQ_T(mst_req_t, mst_aw_chan_t, w_chan_t, mst_ar_chan_t)
`AXI_TYPEDEF_RESP_T(axi_resp_t, b_chan_t, r_chan_t)
slv_req_t slv_req;
mst_req_t mst_req;
axi_resp_t slv_resp, mst_resp;
`AXI_ASSIGN_TO_REQ(slv_req, slv)
`AXI_ASSIGN_FROM_RESP(slv, slv_resp)
`AXI_ASSIGN_FROM_REQ(mst, mst_req)
`AXI_ASSIGN_TO_RESP(mst_resp, mst)
axi_modify_address #(
.slv_req_t ( slv_req_t ),
.mst_addr_t ( mst_addr_t ),
.mst_req_t ( mst_req_t ),
.axi_resp_t ( axi_resp_t )
) i_axi_modify_address (
.slv_req_i ( slv_req ),
.slv_resp_o ( slv_resp ),
.mst_req_o ( mst_req ),
.mst_resp_i ( mst_resp ),
.mst_aw_addr_i,
.mst_ar_addr_i
);
// pragma translate_off
`ifndef VERILATOR
initial begin
assert(AXI_SLV_PORT_ADDR_WIDTH > 0);
assert(AXI_MST_PORT_ADDR_WIDTH > 0);
assert(AXI_DATA_WIDTH > 0);
assert(AXI_ID_WIDTH > 0);
end
`endif
// pragma translate_on
endmodule
// Copyright (c) 2014-2019 ETH Zurich, University of Bologna
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Authors:
// - Wolfgang Roenninger <wroennin@iis.ee.ethz.ch>
// - Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
// - Andreas Kurth <akurth@iis.ee.ethz.ch>
// - Stefan Mach <smach@iis.ee.ethz.ch>
// Multiple AXI4 cuts.
//
// These can be used to relax timing pressure on very long AXI busses.
module axi_multicut #(
parameter int unsigned NoCuts = 32'd1, // Number of cuts.
// AXI channel structs
parameter type aw_chan_t = logic,
parameter type w_chan_t = logic,
parameter type b_chan_t = logic,
parameter type ar_chan_t = logic,
parameter type r_chan_t = logic,
// AXI request & response structs
parameter type axi_req_t = logic,
parameter type axi_resp_t = logic
) (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
// slave port
input axi_req_t slv_req_i,
output axi_resp_t slv_resp_o,
// master port
output axi_req_t mst_req_o,
input axi_resp_t mst_resp_i
);
if (NoCuts == '0) begin : gen_no_cut
// degenerate case, connect input to output
assign mst_req_o = slv_req_i;
assign slv_resp_o = mst_resp_i;
end else begin : gen_axi_cut
// instantiate all needed cuts
axi_req_t [NoCuts:0] cut_req;
axi_resp_t [NoCuts:0] cut_resp;
// connect slave to the lowest index
assign cut_req[0] = slv_req_i;
assign slv_resp_o = cut_resp[0];
// AXI cuts
for (genvar i = 0; i < NoCuts; i++) begin : gen_axi_cuts
axi_cut #(
.Bypass ( 1'b0 ),
.aw_chan_t ( aw_chan_t ),
.w_chan_t ( w_chan_t ),
.b_chan_t ( b_chan_t ),
.ar_chan_t ( ar_chan_t ),
.r_chan_t ( r_chan_t ),
.axi_req_t ( axi_req_t ),
.axi_resp_t ( axi_resp_t )
) i_cut (
.clk_i,
.rst_ni,
.slv_req_i ( cut_req[i] ),
.slv_resp_o ( cut_resp[i] ),
.mst_req_o ( cut_req[i+1] ),
.mst_resp_i ( cut_resp[i+1] )
);
end
// connect master to the highest index
assign mst_req_o = cut_req[NoCuts];
assign cut_resp[NoCuts] = mst_resp_i;
end
// Check the invariants
// pragma translate_off
`ifndef VERILATOR
initial begin
assert(NoCuts >= 0);
end
`endif
// pragma translate_on
endmodule
`include "axi/assign.svh"
`include "axi/typedef.svh"
// interface wrapper
module axi_multicut_intf #(
parameter int unsigned ADDR_WIDTH = 0, // The address width.
parameter int unsigned DATA_WIDTH = 0, // The data width.
parameter int unsigned ID_WIDTH = 0, // The ID width.
parameter int unsigned USER_WIDTH = 0, // The user data width.
parameter int unsigned NUM_CUTS = 0 // The number of cuts.
) (
input logic clk_i,
input logic rst_ni,
AXI_BUS.Slave in,
AXI_BUS.Master out
);
typedef logic [ID_WIDTH-1:0] id_t;
typedef logic [ADDR_WIDTH-1:0] addr_t;
typedef logic [DATA_WIDTH-1:0] data_t;
typedef logic [DATA_WIDTH/8-1:0] strb_t;
typedef logic [USER_WIDTH-1:0] user_t;
`AXI_TYPEDEF_AW_CHAN_T(aw_chan_t, addr_t, id_t, user_t)
`AXI_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t, user_t)
`AXI_TYPEDEF_B_CHAN_T(b_chan_t, id_t, user_t)
`AXI_TYPEDEF_AR_CHAN_T(ar_chan_t, addr_t, id_t, user_t)
`AXI_TYPEDEF_R_CHAN_T(r_chan_t, data_t, id_t, user_t)
`AXI_TYPEDEF_REQ_T(axi_req_t, aw_chan_t, w_chan_t, ar_chan_t)
`AXI_TYPEDEF_RESP_T(axi_resp_t, b_chan_t, r_chan_t)
axi_req_t slv_req, mst_req;
axi_resp_t slv_resp, mst_resp;
`AXI_ASSIGN_TO_REQ(slv_req, in)
`AXI_ASSIGN_FROM_RESP(in, slv_resp)
`AXI_ASSIGN_FROM_REQ(out, mst_req)
`AXI_ASSIGN_TO_RESP(mst_resp, out)
axi_multicut #(
.NoCuts ( NUM_CUTS ),
.aw_chan_t ( aw_chan_t ),
.w_chan_t ( w_chan_t ),
.b_chan_t ( b_chan_t ),
.ar_chan_t ( ar_chan_t ),
.r_chan_t ( r_chan_t ),
.axi_req_t ( axi_req_t ),
.axi_resp_t ( axi_resp_t )
) i_axi_multicut (
.clk_i,
.rst_ni,
.slv_req_i ( slv_req ),
.slv_resp_o ( slv_resp ),
.mst_req_o ( mst_req ),
.mst_resp_i ( mst_resp )
);
// Check the invariants.
// pragma translate_off
`ifndef VERILATOR
initial begin
assert (ADDR_WIDTH > 0) else $fatal(1, "Wrong addr width parameter");
assert (DATA_WIDTH > 0) else $fatal(1, "Wrong data width parameter");
assert (ID_WIDTH > 0) else $fatal(1, "Wrong id width parameter");
assert (USER_WIDTH > 0) else $fatal(1, "Wrong user width parameter");
assert (in.AXI_ADDR_WIDTH == ADDR_WIDTH) else $fatal(1, "Wrong interface definition");
assert (in.AXI_DATA_WIDTH == DATA_WIDTH) else $fatal(1, "Wrong interface definition");
assert (in.AXI_ID_WIDTH == ID_WIDTH) else $fatal(1, "Wrong interface definition");
assert (in.AXI_USER_WIDTH == USER_WIDTH) else $fatal(1, "Wrong interface definition");
assert (out.AXI_ADDR_WIDTH == ADDR_WIDTH) else $fatal(1, "Wrong interface definition");
assert (out.AXI_DATA_WIDTH == DATA_WIDTH) else $fatal(1, "Wrong interface definition");
assert (out.AXI_ID_WIDTH == ID_WIDTH) else $fatal(1, "Wrong interface definition");
assert (out.AXI_USER_WIDTH == USER_WIDTH) else $fatal(1, "Wrong interface definition");
end
`endif
// pragma translate_on
endmodule
module axi_lite_multicut_intf #(
// The address width.
parameter int unsigned ADDR_WIDTH = 0,
// The data width.
parameter int unsigned DATA_WIDTH = 0,
// The number of cuts.
parameter int unsigned NUM_CUTS = 0
) (
input logic clk_i ,
input logic rst_ni ,
AXI_LITE.Slave in ,
AXI_LITE.Master out
);
typedef logic [ADDR_WIDTH-1:0] addr_t;
typedef logic [DATA_WIDTH-1:0] data_t;
typedef logic [DATA_WIDTH/8-1:0] strb_t;
`AXI_LITE_TYPEDEF_AW_CHAN_T(aw_chan_t, addr_t)
`AXI_LITE_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t)
`AXI_LITE_TYPEDEF_B_CHAN_T(b_chan_t)
`AXI_LITE_TYPEDEF_AR_CHAN_T(ar_chan_t, addr_t)
`AXI_LITE_TYPEDEF_R_CHAN_T(r_chan_t, data_t)
`AXI_LITE_TYPEDEF_REQ_T(axi_req_t, aw_chan_t, w_chan_t, ar_chan_t)
`AXI_LITE_TYPEDEF_RESP_T(axi_resp_t, b_chan_t, r_chan_t)
axi_req_t slv_req, mst_req;
axi_resp_t slv_resp, mst_resp;
`AXI_LITE_ASSIGN_TO_REQ(slv_req, in)
`AXI_LITE_ASSIGN_FROM_RESP(in, slv_resp)
`AXI_LITE_ASSIGN_FROM_REQ(out, mst_req)
`AXI_LITE_ASSIGN_TO_RESP(mst_resp, out)
axi_multicut #(
.NoCuts ( NUM_CUTS ),
.aw_chan_t ( aw_chan_t ),
.w_chan_t ( w_chan_t ),
.b_chan_t ( b_chan_t ),
.ar_chan_t ( ar_chan_t ),
.r_chan_t ( r_chan_t ),
.axi_req_t ( axi_req_t ),
.axi_resp_t ( axi_resp_t )
) i_axi_multicut (
.clk_i,
.rst_ni,
.slv_req_i ( slv_req ),
.slv_resp_o ( slv_resp ),
.mst_req_o ( mst_req ),
.mst_resp_i ( mst_resp )
);
// Check the invariants.
// pragma translate_off
`ifndef VERILATOR
initial begin
assert (ADDR_WIDTH > 0) else $fatal(1, "Wrong addr width parameter");
assert (DATA_WIDTH > 0) else $fatal(1, "Wrong data width parameter");
assert (in.AXI_ADDR_WIDTH == ADDR_WIDTH) else $fatal(1, "Wrong interface definition");
assert (in.AXI_DATA_WIDTH == DATA_WIDTH) else $fatal(1, "Wrong interface definition");
assert (out.AXI_ADDR_WIDTH == ADDR_WIDTH) else $fatal(1, "Wrong interface definition");
assert (out.AXI_DATA_WIDTH == DATA_WIDTH) else $fatal(1, "Wrong interface definition");
end
`endif
// pragma translate_on
endmodule
axi:
vlog_opts: [
-L common_cells_lib
]
incdirs:
- include
- ../../common_cells/include
files:
# Source files grouped in levels. Files in level 0 have no dependencies on files in this
# package. Files in level 1 only depend on files in level 0, files in level 2 on files in
# levels 1 and 0, etc. Files within a level are ordered alphabetically.
# Level 0
- src/axi_pkg.sv
# Level 1
- src/axi_intf.sv
# Level 2
- src/axi_atop_filter.sv
- src/axi_burst_splitter.sv
- src/axi_cdc_dst.sv
- src/axi_cdc_src.sv
- src/axi_cut.sv
- src/axi_delayer.sv
- src/axi_demux.sv
- src/axi_dw_downsizer.sv
- src/axi_dw_upsizer.sv
- src/axi_id_remap.sv
- src/axi_id_prepend.sv
- src/axi_isolate.sv
- src/axi_join.sv
- src/axi_lite_demux.sv
- src/axi_lite_join.sv
- src/axi_lite_mailbox.sv
- src/axi_lite_mux.sv
- src/axi_lite_regs.sv
- src/axi_lite_to_apb.sv
- src/axi_lite_to_axi.sv
- src/axi_modify_address.sv
- src/axi_mux.sv
- src/axi_serializer.sv
# Level 3
- src/axi_cdc.sv
- src/axi_err_slv.sv
- src/axi_dw_converter.sv
- src/axi_id_serialize.sv
- src/axi_multicut.sv
- src/axi_to_axi_lite.sv
# Level 4
- src/axi_iw_converter.sv
- src/axi_lite_xbar.sv
- src/axi_xbar.sv
axi_sim:
files:
- src/axi_sim_mem.sv
- src/axi_test.sv
flags:
- skip_synthesis
- only_local
// Copyright (c) 2019 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Authors:
// - Wolfgang Roenninger <wroennin@iis.ee.ethz.ch>
// - Andreas Kurth <akurth@iis.ee.ethz.ch>
// Description: Simple test for showing address wrapping behavior of the function
// `axi_pkg::beat_addr`
`include "axi/assign.svh"
/// Test bench for address generation
module tb_axi_addr_test #(
/// Number of calculated AX transfers
int unsigned NumTests = 32'd10000,
/// Print each calculated address
bit PrintDbg = 1'b0
);
localparam int unsigned AxiIdWidth = 32'd1;
localparam int unsigned AxiAddrWidth = 32'd16;
localparam int unsigned AxiDataWidth = 32'd1024;
localparam int unsigned AxiUserWidth = 32'd1;
// Sim print config, how many transactions
localparam int unsigned PrintTnx = 1000;
localparam int unsigned NoReads = 0;
localparam int unsigned NoWrites = NumTests;
typedef logic [AxiAddrWidth:0] addr_t;
/// The data transferred on a beat on the AW/AR channels.
class ax_transfer;
rand addr_t addr = '0;
rand axi_pkg::len_t len = '0;
rand axi_pkg::size_t size = '0;
rand axi_pkg::burst_t burst = '0;
endclass
// Random master no Transactions
localparam int unsigned NoPendingDut = 16;
// timing parameters
localparam time CyclTime = 10ns;
localparam time ApplTime = 2ns;
localparam time TestTime = 8ns;
typedef axi_test::axi_rand_master #(
// AXI interface parameters
.AW ( AxiAddrWidth ),
.DW ( AxiDataWidth ),
.IW ( AxiIdWidth ),
.UW ( AxiUserWidth ),
// Stimuli application and test time
.TA ( ApplTime ),
.TT ( TestTime ),
// Enable burst types
.AXI_BURST_FIXED ( 1'b1 ),
.AXI_BURST_INCR ( 1'b1 ),
.AXI_BURST_WRAP ( 1'b1 )
) axi_rand_master_t;
typedef axi_test::axi_rand_slave #(
// AXI interface parameters
.AW ( AxiAddrWidth ),
.DW ( AxiDataWidth ),
.IW ( AxiIdWidth ),
.UW ( AxiUserWidth ),
// Stimuli application and test time
.TA ( ApplTime ),
.TT ( TestTime )
) axi_rand_slave_t;
// -------------
// DUT signals
// -------------
logic clk;
logic rst_n;
logic end_of_sim;
AXI_BUS_DV #(
.AXI_ADDR_WIDTH ( AxiAddrWidth ),
.AXI_DATA_WIDTH ( AxiDataWidth ),
.AXI_ID_WIDTH ( AxiIdWidth ),
.AXI_USER_WIDTH ( AxiUserWidth )
) master_dv (clk);
AXI_BUS_DV #(
.AXI_ADDR_WIDTH ( AxiAddrWidth ),
.AXI_DATA_WIDTH ( AxiDataWidth ),
.AXI_ID_WIDTH ( AxiIdWidth ),
.AXI_USER_WIDTH ( AxiUserWidth )
) slave_dv (clk);
`AXI_ASSIGN(slave_dv, master_dv)
//-----------------------------------
// Clock generator
//-----------------------------------
clk_rst_gen #(
.ClkPeriod ( CyclTime ),
.RstClkCycles( 5 )
) i_clk_gen (
.clk_o (clk),
.rst_no(rst_n)
);
initial begin : proc_axi_master
automatic axi_rand_master_t axi_rand_master = new(master_dv);
end_of_sim <= 1'b0;
axi_rand_master.add_memory_region(16'h0000, 16'hFFFF, axi_pkg::DEVICE_NONBUFFERABLE);
axi_rand_master.add_memory_region(16'h0000, 16'hFFFF, axi_pkg::WTHRU_NOALLOCATE);
axi_rand_master.add_memory_region(16'h0000, 16'hFFFF, axi_pkg::WBACK_RWALLOCATE);
axi_rand_master.reset();
@(posedge rst_n);
axi_rand_master.run(0, NumTests);
end_of_sim <= 1'b1;
repeat (10000) @(posedge clk);
$stop();
end
initial begin : proc_axi_slave
automatic axi_rand_slave_t axi_rand_slave = new(slave_dv);
axi_rand_slave.reset();
@(posedge rst_n);
axi_rand_slave.run();
end
initial begin : proc_sim_progress
automatic int unsigned aw = 0;
automatic int unsigned ar = 0;
automatic bit aw_printed = 1'b0;
automatic bit ar_printed = 1'b0;
@(posedge rst_n);
forever begin
@(posedge clk);
#TestTime;
if (master_dv.aw_valid && master_dv.aw_ready) begin
aw++;
end
if (master_dv.ar_valid && master_dv.ar_ready) begin
ar++;
end
if ((aw % PrintTnx == 0) && ! aw_printed) begin
$display("%t> Transmit AW %d of %d.", $time(), aw, NoWrites);
aw_printed = 1'b1;
end
if ((ar % PrintTnx == 0) && !ar_printed) begin
$display("%t> Transmit AR %d of %d.", $time(), ar, NoReads);
ar_printed = 1'b1;
end
if (aw % PrintTnx == 1) begin
aw_printed = 1'b0;
end
if (ar % PrintTnx == 1) begin
ar_printed = 1'b0;
end
if (end_of_sim) begin
$info("All transactions completed.");
break;
end
end
end
// Test Address queue
ax_transfer ax_queue[$];
addr_t gold_addr[$];
initial begin : generate_tests
automatic logic rand_success;
automatic ax_transfer ax_beat;
forever begin
@(posedge clk);
#TestTime;
if (master_dv.aw_valid && master_dv.aw_ready) begin
ax_beat = new;
ax_beat.addr = master_dv.aw_addr;
ax_beat.len = master_dv.aw_len;
ax_beat.size = master_dv.aw_size;
ax_beat.burst = master_dv.aw_burst;
ax_queue.push_back(ax_beat);
end
end
end
initial begin : proc_test
automatic ax_transfer ax_beat;
automatic addr_t test_addr, exp_addr;
for (int unsigned i = 0; i < NumTests; i++) begin
wait (ax_queue.size());
// get current transfer
ax_beat = ax_queue.pop_front();
if (PrintDbg) begin
print_ax(ax_beat);
end
// golden model derived from pseudocode from A-52
data_transfer(ax_beat.addr, (2**ax_beat.size), (ax_beat.len+1), ax_beat.burst);
// test the calculated addresses
for (int unsigned i = 0; i <= ax_beat.len; i++) begin
test_addr = axi_pkg::beat_addr(ax_beat.addr, ax_beat.size, ax_beat.len, ax_beat.burst, i);
exp_addr = gold_addr.pop_front();
if (PrintDbg) begin
print_addr(test_addr, i);
end
assert (test_addr == exp_addr) else
begin
print_ax(ax_beat);
print_addr(test_addr, i);
$error("Expected ADDR: %0h was ADDR: %0h", exp_addr, test_addr);
end
end
end
end
// golden model derived from pseudocode from A-52
function automatic void data_transfer(addr_t start_addr, int unsigned num_bytes,
int unsigned burst_length, axi_pkg::burst_t mode);
// define boundaries wider than the address, to finf wrapp of addr space
localparam int unsigned large_addr = $bits(addr_t);
typedef logic [large_addr:0] laddr_t;
laddr_t addr;
laddr_t aligned_addr;
bit aligned;
int unsigned dtsize;
laddr_t lower_wrap_boundary;
laddr_t upper_wrap_boundary;
assume (mode inside {axi_pkg::BURST_FIXED, axi_pkg::BURST_INCR, axi_pkg::BURST_WRAP});
addr = laddr_t'(start_addr);
aligned_addr = laddr_t'((addr / num_bytes) * num_bytes);
aligned = (aligned_addr == addr);
dtsize = num_bytes * burst_length;
if (mode == axi_pkg::BURST_WRAP) begin
lower_wrap_boundary = laddr_t'((addr / dtsize) * dtsize);
upper_wrap_boundary = lower_wrap_boundary + dtsize;
end
for (int unsigned n = 1; n <= burst_length; n++) begin
gold_addr.push_back(addr_t'(addr));
// increment address if necessary
if (mode != axi_pkg::BURST_FIXED) begin
if (aligned) begin
addr += num_bytes;
end else begin
addr = aligned_addr + num_bytes;
aligned = 1'b1;
end
if (mode == axi_pkg::BURST_WRAP && (addr >= upper_wrap_boundary)) begin
addr = lower_wrap_boundary;
end
end
end
endfunction : data_transfer
function automatic void print_ax (ax_transfer ax);
$display("####################################################################",);
$display("AX transfer with:");
case (ax.burst)
axi_pkg::BURST_FIXED: $display("TYPE: BURST_FIXED");
axi_pkg::BURST_INCR: $display("TYPE: BURST_INCR");
axi_pkg::BURST_WRAP: $display("TYPE: BURST_WRAP");
default : $error("TYPE: NOT_DEFINED");
endcase
$display("ADDR: %0h", ax.addr);
$display("SIZE: %0h", ax.size);
$display("LEN: %0h", ax.len);
endfunction : print_ax
function automatic void print_addr(addr_t addr, int unsigned i_addr);
$display("i_beat: %0h ADDR: %0h", i_addr, addr);
endfunction : print_addr
endmodule
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate /tb_axi_atop_filter/clk
add wave -noupdate /tb_axi_atop_filter/rst_n
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/aw_id
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/aw_addr
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/aw_len
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/aw_size
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/aw_burst
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/aw_lock
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/aw_cache
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/aw_prot
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/aw_qos
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/aw_region
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/aw_atop
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/aw_user
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/aw_valid
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/aw_ready
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/w_data
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/w_strb
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/w_last
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/w_user
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/w_valid
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/w_ready
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/b_id
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/b_resp
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/b_user
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/b_valid
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/b_ready
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/ar_id
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/ar_addr
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/ar_len
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/ar_size
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/ar_burst
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/ar_lock
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/ar_cache
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/ar_prot
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/ar_qos
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/ar_region
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/ar_user
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/ar_valid
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/ar_ready
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/r_id
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/r_data
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/r_resp
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/r_last
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/r_user
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/r_valid
add wave -noupdate -expand -group upstream /tb_axi_atop_filter/upstream/r_ready
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/aw_id
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/aw_addr
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/aw_len
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/aw_size
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/aw_burst
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/aw_lock
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/aw_cache
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/aw_prot
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/aw_qos
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/aw_region
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/aw_atop
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/aw_user
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/aw_valid
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/aw_ready
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/w_data
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/w_strb
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/w_last
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/w_user
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/w_valid
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/w_ready
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/b_id
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/b_resp
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/b_user
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/b_valid
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/b_ready
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/ar_id
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/ar_addr
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/ar_len
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/ar_size
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/ar_burst
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/ar_lock
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/ar_cache
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/ar_prot
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/ar_qos
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/ar_region
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/ar_user
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/ar_valid
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/ar_ready
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/r_id
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/r_data
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/r_resp
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/r_last
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/r_user
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/r_valid
add wave -noupdate -expand -group downstream /tb_axi_atop_filter/downstream/r_ready
TreeUpdate [SetDefaultTree]
configure wave -namecolwidth 150
configure wave -valuecolwidth 100
configure wave -justifyvalue left
configure wave -signalnamewidth 1
configure wave -snapdistance 10
configure wave -datasetprefix 0
configure wave -rowmargin 4
configure wave -childrowmargin 2
configure wave -gridoffset 0
configure wave -gridperiod 1
configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits ns
update
// Copyright 2019-2020 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Authors:
// - Andreas Kurth <akurth@iis.ee.ethz.ch>
// - Wolfgang Roenninger <wroennin@iis.ee.ethz.ch>
`include "axi/typedef.svh"
`include "axi/assign.svh"
module tb_axi_cdc #(
// AXI Parameters
parameter int unsigned AXI_AW = 32,
parameter int unsigned AXI_DW = 64,
parameter int unsigned AXI_IW = 4,
parameter int unsigned AXI_UW = 2,
parameter int unsigned AXI_MAX_READ_TXNS = 10,
parameter int unsigned AXI_MAX_WRITE_TXNS = 12,
// TB Parameters
parameter time TCLK_UPSTREAM = 10ns,
parameter time TA_UPSTREAM = TCLK_UPSTREAM * 1/4,
parameter time TT_UPSTREAM = TCLK_UPSTREAM * 3/4,
parameter time TCLK_DOWNSTREAM = 3ns,
parameter time TA_DOWNSTREAM = TCLK_DOWNSTREAM * 1/4,
parameter time TT_DOWNSTREAM = TCLK_DOWNSTREAM * 3/4,
parameter int unsigned REQ_MIN_WAIT_CYCLES = 0,
parameter int unsigned REQ_MAX_WAIT_CYCLES = 10,
parameter int unsigned RESP_MIN_WAIT_CYCLES = 0,
parameter int unsigned RESP_MAX_WAIT_CYCLES = REQ_MAX_WAIT_CYCLES/2,
parameter int unsigned N_TXNS = 1000
);
localparam int unsigned N_RD_TXNS = N_TXNS / 2;
localparam int unsigned N_WR_TXNS = N_TXNS / 2;
// Clocks and Resets
logic upstream_clk,
downstream_clk,
upstream_rst_n,
downstream_rst_n;
clk_rst_gen #(
.ClkPeriod (TCLK_UPSTREAM),
.RstClkCycles (5)
) i_clk_rst_gen_upstream (
.clk_o (upstream_clk),
.rst_no (upstream_rst_n)
);
clk_rst_gen #(
.ClkPeriod (TCLK_DOWNSTREAM),
.RstClkCycles (5)
) i_clk_rst_gen_downstream (
.clk_o (downstream_clk),
.rst_no (downstream_rst_n)
);
// AXI Interfaces
AXI_BUS_DV #(
.AXI_ADDR_WIDTH (AXI_AW),
.AXI_DATA_WIDTH (AXI_DW),
.AXI_ID_WIDTH (AXI_IW),
.AXI_USER_WIDTH (AXI_UW)
) upstream_dv (
.clk_i (upstream_clk)
);
AXI_BUS #(
.AXI_ADDR_WIDTH (AXI_AW),
.AXI_DATA_WIDTH (AXI_DW),
.AXI_ID_WIDTH (AXI_IW),
.AXI_USER_WIDTH (AXI_UW)
) upstream ();
`AXI_ASSIGN(upstream, upstream_dv)
AXI_BUS_DV #(
.AXI_ADDR_WIDTH (AXI_AW),
.AXI_DATA_WIDTH (AXI_DW),
.AXI_ID_WIDTH (AXI_IW),
.AXI_USER_WIDTH (AXI_UW)
) downstream_dv (
.clk_i (downstream_clk)
);
AXI_BUS #(
.AXI_ADDR_WIDTH (AXI_AW),
.AXI_DATA_WIDTH (AXI_DW),
.AXI_ID_WIDTH (AXI_IW),
.AXI_USER_WIDTH (AXI_UW)
) downstream ();
`AXI_ASSIGN(downstream_dv, downstream)
// AXI Channel Structs
typedef logic [AXI_AW-1:0] addr_t;
typedef logic [AXI_DW-1:0] data_t;
typedef logic [AXI_IW-1:0] id_t;
typedef logic [AXI_DW/8-1:0] strb_t;
typedef logic [AXI_UW-1:0] user_t;
`AXI_TYPEDEF_AW_CHAN_T(aw_chan_t, addr_t, id_t, user_t)
`AXI_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t, user_t)
`AXI_TYPEDEF_B_CHAN_T(b_chan_t, id_t, user_t)
`AXI_TYPEDEF_AR_CHAN_T(ar_chan_t, addr_t, id_t, user_t)
`AXI_TYPEDEF_R_CHAN_T(r_chan_t, data_t, id_t, user_t)
axi_cdc_intf #(
.AXI_ADDR_WIDTH (AXI_AW),
.AXI_DATA_WIDTH (AXI_DW),
.AXI_ID_WIDTH (AXI_IW),
.AXI_USER_WIDTH (AXI_UW),
.LOG_DEPTH (2)
) dut (
.src_clk_i (upstream_clk),
.src_rst_ni (upstream_rst_n),
.src (upstream),
.dst_clk_i (downstream_clk),
.dst_rst_ni (downstream_rst_n),
.dst (downstream)
);
typedef axi_test::axi_rand_master #(
.AW (AXI_AW),
.DW (AXI_DW),
.IW (AXI_IW),
.UW (AXI_UW),
.TA (TA_UPSTREAM),
.TT (TT_UPSTREAM),
.MAX_READ_TXNS (AXI_MAX_READ_TXNS),
.MAX_WRITE_TXNS (AXI_MAX_WRITE_TXNS),
.AX_MIN_WAIT_CYCLES (REQ_MIN_WAIT_CYCLES),
.AX_MAX_WAIT_CYCLES (REQ_MAX_WAIT_CYCLES),
.W_MIN_WAIT_CYCLES (REQ_MIN_WAIT_CYCLES),
.W_MAX_WAIT_CYCLES (REQ_MAX_WAIT_CYCLES),
.RESP_MIN_WAIT_CYCLES (RESP_MIN_WAIT_CYCLES),
.RESP_MAX_WAIT_CYCLES (RESP_MAX_WAIT_CYCLES),
.AXI_MAX_BURST_LEN (16)
) axi_master_t;
axi_master_t axi_master = new(upstream_dv);
initial begin
wait (upstream_rst_n);
axi_master.run(N_RD_TXNS, N_WR_TXNS);
end
typedef axi_test::axi_rand_slave #(
.AW (AXI_AW),
.DW (AXI_DW),
.IW (AXI_IW),
.UW (AXI_UW),
.TA (TA_DOWNSTREAM),
.TT (TT_DOWNSTREAM),
.AX_MIN_WAIT_CYCLES (RESP_MIN_WAIT_CYCLES),
.AX_MAX_WAIT_CYCLES (RESP_MAX_WAIT_CYCLES),
.R_MIN_WAIT_CYCLES (RESP_MIN_WAIT_CYCLES),
.R_MAX_WAIT_CYCLES (RESP_MAX_WAIT_CYCLES),
.RESP_MIN_WAIT_CYCLES (RESP_MIN_WAIT_CYCLES),
.RESP_MAX_WAIT_CYCLES (RESP_MAX_WAIT_CYCLES)
) axi_slave_t;
axi_slave_t axi_slave = new(downstream_dv);
initial begin
wait (downstream_rst_n);
axi_slave.run();
end
ar_chan_t mst_ar, slv_ar, ar_queue[$];
aw_chan_t mst_aw, slv_aw, aw_queue[$];
b_chan_t mst_b, slv_b, b_queue[$];
r_chan_t mst_r, slv_r, r_queue[$];
w_chan_t mst_w, slv_w, w_queue[$];
`AXI_ASSIGN_TO_AR(mst_ar, upstream)
`AXI_ASSIGN_TO_AR(slv_ar, downstream)
`AXI_ASSIGN_TO_AW(mst_aw, upstream)
`AXI_ASSIGN_TO_AW(slv_aw, downstream)
`AXI_ASSIGN_TO_B(mst_b, upstream)
`AXI_ASSIGN_TO_B(slv_b, downstream)
`AXI_ASSIGN_TO_R(mst_r, upstream)
`AXI_ASSIGN_TO_R(slv_r, downstream)
`AXI_ASSIGN_TO_W(mst_w, upstream)
`AXI_ASSIGN_TO_W(slv_w, downstream)
logic mst_done = 1'b0;
// Monitor and check upstream
initial begin
automatic b_chan_t exp_b;
automatic r_chan_t exp_r;
automatic int unsigned rd_cnt = 0, wr_cnt = 0;
forever begin
@(posedge upstream_clk);
#(TT_UPSTREAM);
if (upstream.aw_valid && upstream.aw_ready) begin
aw_queue.push_back(mst_aw);
end
if (upstream.w_valid && upstream.w_ready) begin
w_queue.push_back(mst_w);
end
if (upstream.b_valid && upstream.b_ready) begin
exp_b = b_queue.pop_front();
assert (mst_b == exp_b);
wr_cnt++;
end
if (upstream.ar_valid && upstream.ar_ready) begin
ar_queue.push_back(mst_ar);
end
if (upstream.r_valid && upstream.r_ready) begin
exp_r = r_queue.pop_front();
assert (mst_r == exp_r);
if (upstream.r_last) begin
rd_cnt++;
end
end
if (rd_cnt == N_RD_TXNS && wr_cnt == N_WR_TXNS) begin
mst_done = 1'b1;
end
end
end
// Monitor and check downstream
initial begin
automatic ar_chan_t exp_ar;
automatic aw_chan_t exp_aw;
automatic w_chan_t exp_w;
forever begin
@(posedge downstream_clk);
#(TT_DOWNSTREAM);
if (downstream.aw_valid && downstream.aw_ready) begin
exp_aw = aw_queue.pop_front();
assert (slv_aw == exp_aw);
end
if (downstream.w_valid && downstream.w_ready) begin
exp_w = w_queue.pop_front();
assert (slv_w == exp_w);
end
if (downstream.b_valid && downstream.b_ready) begin
b_queue.push_back(slv_b);
end
if (downstream.ar_valid && downstream.ar_ready) begin
exp_ar = ar_queue.pop_front();
assert (slv_ar == exp_ar);
end
if (downstream.r_valid && downstream.r_ready) begin
r_queue.push_back(slv_r);
end
end
end
// Terminate simulation after all transactions have completed.
initial begin
wait (mst_done);
#(10*TCLK_UPSTREAM);
$finish();
end
endmodule
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Authors:
// - Andreas Kurth <akurth@iis.ee.ethz.ch>
// - Florian Zaruba <zarubaf@iis.ee.ethz.ch>
`include "axi/assign.svh"
module tb_axi_delayer;
parameter AW = 32;
parameter DW = 32;
parameter IW = 8;
parameter UW = 8;
parameter TS = 4;
localparam tCK = 1ns;
logic clk = 0;
logic rst = 1;
logic done = 0;
AXI_BUS_DV #(
.AXI_ADDR_WIDTH(AW),
.AXI_DATA_WIDTH(DW),
.AXI_ID_WIDTH(IW),
.AXI_USER_WIDTH(UW)
) axi_slave_dv(clk), axi_master_dv(clk);
AXI_BUS #(
.AXI_ADDR_WIDTH(AW),
.AXI_DATA_WIDTH(DW),
.AXI_ID_WIDTH(IW),
.AXI_USER_WIDTH(UW)
) axi_slave(), axi_master();
`AXI_ASSIGN(axi_slave_dv, axi_slave)
`AXI_ASSIGN(axi_master, axi_master_dv)
axi_delayer_intf #(
.AXI_ADDR_WIDTH ( AW ),
.AXI_DATA_WIDTH ( DW ),
.AXI_ID_WIDTH ( IW ),
.AXI_USER_WIDTH ( UW ),
.FIXED_DELAY_INPUT ( 0 ),
.STALL_RANDOM_INPUT ( 1 )
) i_axi_delayer (
.clk_i ( clk ),
.rst_ni ( rst ),
.slv ( axi_master ),
.mst ( axi_slave )
);
axi_test::axi_driver #(.AW(AW), .DW(DW), .IW(IW), .UW(UW), .TA(200ps), .TT(700ps)) axi_slave_drv = new(axi_slave_dv);
axi_test::axi_driver #(.AW(AW), .DW(DW), .IW(IW), .UW(UW), .TA(200ps), .TT(700ps)) axi_master_drv = new(axi_master_dv);
initial begin
#tCK;
rst <= 0;
#tCK;
rst <= 1;
#tCK;
while (!done) begin
clk <= 1;
#(tCK/2);
clk <= 0;
#(tCK/2);
end
end
initial begin
automatic axi_test::axi_ax_beat #(.AW(AW), .IW(IW), .UW(UW)) ax_beat = new;
automatic axi_test::axi_w_beat #(.DW(DW), .UW(UW)) w_beat = new;
automatic axi_test::axi_b_beat #(.IW(IW), .UW(UW)) b_beat;
automatic logic rand_success;
axi_master_drv.reset_master();
@(posedge clk);
repeat (200) begin
@(posedge clk);
rand_success = ax_beat.randomize(); assert(rand_success);
axi_master_drv.send_aw(ax_beat);
w_beat.w_data = 'hcafebabe;
axi_master_drv.send_w(w_beat);
end
repeat (200) axi_master_drv.recv_b(b_beat);
done = 1;
end
initial begin
automatic axi_test::axi_ax_beat #(.AW(AW), .IW(IW), .UW(UW)) ax_beat;
automatic axi_test::axi_w_beat #(.DW(DW), .UW(UW)) w_beat;
automatic axi_test::axi_b_beat #(.IW(IW), .UW(UW)) b_beat = new;
automatic int b_id_queue[$];
axi_slave_drv.reset_slave();
@(posedge clk);
repeat (200) begin
axi_slave_drv.recv_aw(ax_beat);
$info("AXI AW: addr %h", ax_beat.ax_addr);
axi_slave_drv.recv_w(w_beat);
$info("AXI W: data %h, strb %h", w_beat.w_data, w_beat.w_strb);
b_id_queue.push_back(ax_beat.ax_id);
end
while (b_id_queue.size() != 0) begin
b_beat.b_id = b_id_queue.pop_front();
axi_slave_drv.send_b(b_beat);
end
end
// vsim -voptargs=+acc work.tb_axi_delayer
endmodule
add wave -position insertpoint \
sim:/tb_axi_dw_downsizer/i_dw_converter/i_axi_dw_converter/gen_dw_downsize/i_axi_dw_downsizer/AxiSlvPortDataWidth \
sim:/tb_axi_dw_downsizer/i_dw_converter/i_axi_dw_converter/gen_dw_downsize/i_axi_dw_downsizer/AxiMstPortDataWidth \
sim:/tb_axi_dw_downsizer/i_dw_converter/i_axi_dw_converter/gen_dw_downsize/i_axi_dw_downsizer/*
// Copyright 2020 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Authors:
// - Matheus Cavalcante <matheusd@iis.ee.ethz.ch>
`include "axi/assign.svh"
module tb_axi_dw_downsizer #(
// AXI Parameters
parameter int unsigned TbAxiAddrWidth = 64 ,
parameter int unsigned TbAxiIdWidth = 4 ,
parameter int unsigned TbAxiSlvPortDataWidth = 64 ,
parameter int unsigned TbAxiMstPortDataWidth = 32 ,
parameter int unsigned TbAxiUserWidth = 8 ,
// TB Parameters
parameter time TbCyclTime = 10ns,
parameter time TbApplTime = 2ns ,
parameter time TbTestTime = 8ns
);
/*********************
* CLOCK GENERATOR *
*********************/
logic clk;
logic rst_n;
logic eos;
clk_rst_gen #(
.ClkPeriod (TbCyclTime),
.RstClkCycles (5 )
) i_clk_rst_gen (
.clk_o (clk ),
.rst_no(rst_n)
);
/*********
* AXI *
*********/
// Master port
AXI_BUS_DV #(
.AXI_ADDR_WIDTH(TbAxiAddrWidth ),
.AXI_DATA_WIDTH(TbAxiSlvPortDataWidth),
.AXI_ID_WIDTH (TbAxiIdWidth ),
.AXI_USER_WIDTH(TbAxiUserWidth )
) master_dv (
.clk_i(clk)
);
AXI_BUS #(
.AXI_ADDR_WIDTH(TbAxiAddrWidth ),
.AXI_DATA_WIDTH(TbAxiSlvPortDataWidth),
.AXI_ID_WIDTH (TbAxiIdWidth ),
.AXI_USER_WIDTH(TbAxiUserWidth )
) master ();
`AXI_ASSIGN(master, master_dv)
axi_test::axi_rand_master #(
.AW (TbAxiAddrWidth ),
.DW (TbAxiSlvPortDataWidth),
.IW (TbAxiIdWidth ),
.UW (TbAxiUserWidth ),
.TA (TbApplTime ),
.TT (TbTestTime ),
.MAX_READ_TXNS (8 ),
.MAX_WRITE_TXNS (8 ),
.AXI_BURST_FIXED(1'b0 ),
.AXI_ATOPS (1'b1 )
) master_drv = new (master_dv);
// Slave port
AXI_BUS_DV #(
.AXI_ADDR_WIDTH(TbAxiAddrWidth ),
.AXI_DATA_WIDTH(TbAxiMstPortDataWidth),
.AXI_ID_WIDTH (TbAxiIdWidth ),
.AXI_USER_WIDTH(TbAxiUserWidth )
) slave_dv (
.clk_i(clk)
);
AXI_BUS #(
.AXI_ADDR_WIDTH(TbAxiAddrWidth ),
.AXI_DATA_WIDTH(TbAxiMstPortDataWidth),
.AXI_ID_WIDTH (TbAxiIdWidth ),
.AXI_USER_WIDTH(TbAxiUserWidth )
) slave ();
axi_test::axi_rand_slave #(
.AW(TbAxiAddrWidth ),
.DW(TbAxiMstPortDataWidth),
.IW(TbAxiIdWidth ),
.UW(TbAxiUserWidth ),
.TA(TbApplTime ),
.TT(TbTestTime )
) slave_drv = new (slave_dv);
`AXI_ASSIGN(slave_dv, slave)
/*********
* DUT *
*********/
axi_dw_converter_intf #(
.AXI_MAX_READS (4 ),
.AXI_ADDR_WIDTH (TbAxiAddrWidth ),
.AXI_ID_WIDTH (TbAxiIdWidth ),
.AXI_SLV_PORT_DATA_WIDTH(TbAxiSlvPortDataWidth),
.AXI_MST_PORT_DATA_WIDTH(TbAxiMstPortDataWidth),
.AXI_USER_WIDTH (TbAxiUserWidth )
) i_dw_converter (
.clk_i (clk ),
.rst_ni(rst_n ),
.slv (master),
.mst (slave )
);
/*************
* DRIVERS *
*************/
initial begin
eos = 1'b0;
// Configuration
slave_drv.reset() ;
master_drv.reset() ;
master_drv.add_memory_region({TbAxiAddrWidth{1'b0}}, {TbAxiAddrWidth{1'b1}}, axi_pkg::WTHRU_NOALLOCATE);
// Wait for the reset before sending requests
@(posedge rst_n);
fork
// Act as a sink
slave_drv.run() ;
master_drv.run(200, 200);
join_any
// Done
repeat (10) @(posedge clk);
eos = 1'b1;
end
/*************
* MONITOR *
*************/
initial begin : proc_monitor
static tb_axi_dw_pkg::axi_dw_downsizer_monitor #(
.AxiAddrWidth (TbAxiAddrWidth ),
.AxiMstPortDataWidth(TbAxiMstPortDataWidth),
.AxiSlvPortDataWidth(TbAxiSlvPortDataWidth),
.AxiIdWidth (TbAxiIdWidth ),
.AxiUserWidth (TbAxiUserWidth ),
.TimeTest (TbTestTime )
) monitor = new (master_dv, slave_dv);
fork
monitor.run();
forever begin
#TbTestTime;
if(eos) begin
monitor.print_result();
$stop() ;
end
@(posedge clk);
end
join
end
// vsim -voptargs=+acc work.tb_axi_dw_downsizer
endmodule : tb_axi_dw_downsizer
add wave -position insertpoint \
sim:/tb_axi_dw_upsizer/i_dw_converter/i_axi_dw_converter/gen_dw_upsize/i_axi_dw_upsizer/AxiSlvPortDataWidth \
sim:/tb_axi_dw_upsizer/i_dw_converter/i_axi_dw_converter/gen_dw_upsize/i_axi_dw_upsizer/AxiMstPortDataWidth \
sim:/tb_axi_dw_upsizer/i_dw_converter/i_axi_dw_converter/gen_dw_upsize/i_axi_dw_upsizer/*
// Copyright 2020 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Authors:
// - Matheus Cavalcante <matheusd@iis.ee.ethz.ch>
`include "axi/assign.svh"
module tb_axi_dw_upsizer #(
// AXI Parameters
parameter int unsigned TbAxiAddrWidth = 64 ,
parameter int unsigned TbAxiIdWidth = 4 ,
parameter int unsigned TbAxiSlvPortDataWidth = 32 ,
parameter int unsigned TbAxiMstPortDataWidth = 64 ,
parameter int unsigned TbAxiUserWidth = 8 ,
// TB Parameters
parameter time TbCyclTime = 10ns,
parameter time TbApplTime = 2ns ,
parameter time TbTestTime = 8ns
);
/*********************
* CLOCK GENERATOR *
*********************/
logic clk;
logic rst_n;
logic eos;
clk_rst_gen #(
.ClkPeriod (TbCyclTime),
.RstClkCycles (5 )
) i_clk_rst_gen (
.clk_o (clk ),
.rst_no(rst_n)
);
/*********
* AXI *
*********/
// Master port
AXI_BUS_DV #(
.AXI_ADDR_WIDTH(TbAxiAddrWidth ),
.AXI_DATA_WIDTH(TbAxiSlvPortDataWidth),
.AXI_ID_WIDTH (TbAxiIdWidth ),
.AXI_USER_WIDTH(TbAxiUserWidth )
) master_dv (
.clk_i(clk)
);
AXI_BUS #(
.AXI_ADDR_WIDTH(TbAxiAddrWidth ),
.AXI_DATA_WIDTH(TbAxiSlvPortDataWidth),
.AXI_ID_WIDTH (TbAxiIdWidth ),
.AXI_USER_WIDTH(TbAxiUserWidth )
) master ();
`AXI_ASSIGN(master, master_dv)
axi_test::axi_rand_master #(
.AW (TbAxiAddrWidth ),
.DW (TbAxiSlvPortDataWidth),
.IW (TbAxiIdWidth ),
.UW (TbAxiUserWidth ),
.TA (TbApplTime ),
.TT (TbTestTime ),
.MAX_READ_TXNS (8 ),
.MAX_WRITE_TXNS(8 ),
.AXI_ATOPS (1'b1 )
) master_drv = new (master_dv);
// Slave port
AXI_BUS_DV #(
.AXI_ADDR_WIDTH(TbAxiAddrWidth ),
.AXI_DATA_WIDTH(TbAxiMstPortDataWidth),
.AXI_ID_WIDTH (TbAxiIdWidth ),
.AXI_USER_WIDTH(TbAxiUserWidth )
) slave_dv (
.clk_i(clk)
);
AXI_BUS #(
.AXI_ADDR_WIDTH(TbAxiAddrWidth ),
.AXI_DATA_WIDTH(TbAxiMstPortDataWidth),
.AXI_ID_WIDTH (TbAxiIdWidth ),
.AXI_USER_WIDTH(TbAxiUserWidth )
) slave ();
axi_test::axi_rand_slave #(
.AW(TbAxiAddrWidth ),
.DW(TbAxiMstPortDataWidth),
.IW(TbAxiIdWidth ),
.UW(TbAxiUserWidth ),
.TA(TbApplTime ),
.TT(TbTestTime )
) slave_drv = new (slave_dv);
`AXI_ASSIGN(slave_dv, slave)
/*********
* DUT *
*********/
axi_dw_converter_intf #(
.AXI_MAX_READS (4 ),
.AXI_ADDR_WIDTH (TbAxiAddrWidth ),
.AXI_ID_WIDTH (TbAxiIdWidth ),
.AXI_SLV_PORT_DATA_WIDTH(TbAxiSlvPortDataWidth),
.AXI_MST_PORT_DATA_WIDTH(TbAxiMstPortDataWidth),
.AXI_USER_WIDTH (TbAxiUserWidth )
) i_dw_converter (
.clk_i (clk ),
.rst_ni(rst_n ),
.slv (master),
.mst (slave )
);
/*************
* DRIVERS *
*************/
initial begin
eos = 1'b0;
// Configuration
slave_drv.reset() ;
master_drv.reset() ;
master_drv.add_memory_region({TbAxiAddrWidth{1'b0}}, {TbAxiAddrWidth{1'b1}}, axi_pkg::WTHRU_NOALLOCATE);
// Wait for the reset before sending requests
@(posedge rst_n);
fork
// Act as a sink
slave_drv.run() ;
master_drv.run(200, 200);
join_any
// Done
repeat (10) @(posedge clk);
eos = 1'b1;
end
/*************
* MONITOR *
*************/
initial begin : proc_monitor
static tb_axi_dw_pkg::axi_dw_upsizer_monitor #(
.AxiAddrWidth (TbAxiAddrWidth ),
.AxiMstPortDataWidth(TbAxiMstPortDataWidth),
.AxiSlvPortDataWidth(TbAxiSlvPortDataWidth),
.AxiIdWidth (TbAxiIdWidth ),
.AxiUserWidth (TbAxiUserWidth ),
.TimeTest (TbTestTime )
) monitor = new (master_dv, slave_dv);
fork
monitor.run();
forever begin
#TbTestTime;
if(eos) begin
monitor.print_result();
$stop() ;
end
@(posedge clk);
end
join
end
// vsim -voptargs=+acc work.tb_axi_dw_upsizer
endmodule : tb_axi_dw_upsizer
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment