Merge branch 'master' into disable_repack_error_message

This commit is contained in:
Jingrong Lin 2024-10-31 10:13:50 +08:00 committed by GitHub
commit f4b087a3a7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
711 changed files with 58178 additions and 17665 deletions

153
.github/labeler.yml vendored
View File

@ -1,103 +1,134 @@
# See https://github.com/actions/labeler#common-examples for defining patterns.
# The globs use "minimatch" syntax found at https://github.com/isaacs/minimatch
# The globs use minimatch syntax found at https://github.com/isaacs/minimatch
#
# WARNING: Due to this file being yaml, any string starting with `*` must be
# wrapped in quotes.
# Third-party tools
ABC:
- abc/*
- abc/**/*
- changed-files:
- any-glob-to-any-file: 'abc/*'
- any-glob-to-any-file: 'abc/**/*'
ACE2:
- ace2/*
- ace2/**/*
- changed-files:
- any-glob-to-any-file: 'ace2/*'
- any-glob-to-any-file: 'ace2/**/*'
VPR:
- vpr/*
- vpr/**/*
- libs/**/*
- changed-files:
- any-glob-to-any-file: 'vpr/*'
- any-glob-to-any-file: 'vpr/**/*'
- any-glob-to-any-file: 'libs/**/*'
# General areas
documentation:
- docs/*
- docs/**/*
- "*README*"
- "*.md"
- tutorial
- "*.rst"
- ".readthedocs.yml"
- changed-files:
- any-glob-to-any-file: 'docs/*'
- any-glob-to-any-file: 'docs/**/*'
- any-glob-to-any-file: '*README*'
- any-glob-to-any-file: '*.md'
- any-glob-to-any-file: 'tutorial'
- any-glob-to-any-file: '*.rst'
- any-glob-to-any-file: '.readthedocs.yml'
github:
- .github/*
- .github/**/*
- changed-files:
- any-glob-to-any-file: '.github/*'
- any-glob-to-any-file: '.github/**/*'
docker:
- Dockerfile
- "*docker*"
- changed-files:
- any-glob-to-any-file: 'Dockerfile'
- any-glob-to-any-file: '*docker*'
build:
- Makefile
- "*.make"
- CMakeLists.txt
- cmake
- changed-files:
- any-glob-to-any-file: 'Makefile'
- any-glob-to-any-file: '*.make'
- any-glob-to-any-file: 'CMakeLists.txt'
- any-glob-to-any-file: 'cmake'
libopenfpga:
- "libopenfpga/**"
- changed-files:
- any-glob-to-any-file: 'libopenfpga/**'
libopenfpga-bitstream:
- "libopenfpga/libfpgabitstream/**"
- changed-files:
- any-glob-to-any-file: 'libopenfpga/libfpgabitstream/**'
libopenfpga-arch-parser:
- "libopenfpga/libarchopenfpga/**"
- changed-files:
- any-glob-to-any-file: 'libopenfpga/libarchopenfpga/**'
libopenfpga-fabric-key:
- "libopenfpga/libfabrickey/**"
- changed-files:
- any-glob-to-any-file: 'libopenfpga/libfabrickey/**'
libopenfpga-shell:
- "libopenfpga/libopenfpgashell/**"
- changed-files:
- any-glob-to-any-file: 'libopenfpga/libopenfpgashell/**'
libopenfpga-utils:
- "libopenfpga/libopenfpgautil/**"
- changed-files:
- any-glob-to-any-file: 'libopenfpga/libopenfpgautil/**'
openfpga-tools:
- "openfpga/**"
- changed-files:
- any-glob-to-any-file: 'openfpga/**'
openfpga-verilog:
- "openfpga/*/fpga_verilog/**"
- changed-files:
- any-glob-to-any-file: 'openfpga/*/fpga_verilog/**'
openfpga-sdc:
- "openfpga/*/fpga_sdc/**"
- changed-files:
- any-glob-to-any-file: 'openfpga/*/fpga_sdc/**'
openfpga-bitstream:
- "openfpga/*/fpga_bitstream/**"
- changed-files:
- any-glob-to-any-file: 'openfpga/*/fpga_bitstream/**'
openfpga-spice:
- "openfpga/*/fpga_spice/**"
- changed-files:
- any-glob-to-any-file: 'openfpga/*/fpga_spice/**'
flow-scripts:
- "openfpga_flow/scripts/**"
- "openfpga_flow/openfpga_shell_scripts/**"
- "openfpga_flow/openfpga_simulation_settings/**"
- "openfpga_flow/misc/**"
- changed-files:
- any-glob-to-any-file: 'openfpga_flow/scripts/**'
- any-glob-to-any-file: 'openfpga_flow/openfpga_shell_scripts/**'
- any-glob-to-any-file: 'openfpga_flow/openfpga_simulation_settings/**'
- any-glob-to-any-file: 'openfpga_flow/misc/**'
architecture-description:
- "openfpga_flow/vpr_arch/**"
- "openfpga_flow/openfpga_arch/**"
- "openfpga_flow/fabric_keys/**"
- changed-files:
- any-glob-to-any-file: 'openfpga_flow/vpr_arch/**'
- any-glob-to-any-file: 'openfpga_flow/openfpga_arch/**'
- any-glob-to-any-file: 'openfpga_flow/fabric_keys/**'
bitstream:
- "openfpga_flow/fabric_keys/**"
- changed-files:
- any-glob-to-any-file: 'openfpga_flow/fabric_keys/**'
cell-library:
- "openfpga_flow/openfpga_cell_library/**"
- "openfpga_flow/tech/**"
- changed-files:
- any-glob-to-any-file: 'openfpga_flow/openfpga_cell_library/**'
- any-glob-to-any-file: 'openfpga_flow/tech/**'
benchmarks:
- "openfpga_flow/benchmarks/**"
- changed-files:
- any-glob-to-any-file: 'openfpga_flow/benchmarks/**'
tests:
- "openfpga_flow/tasks/**"
- changed-files:
- any-glob-to-any-file: 'openfpga_flow/tasks/**'
# Tag pull requests with the languages used to make it easy to see what is
# being used.
lang-hdl:
- "*.v"
- "*.sv"
- changed-files:
- any-glob-to-any-file: '*.v'
- any-glob-to-any-file: '*.sv'
lang-cpp:
- "*.c*"
- "*.h"
- changed-files:
- any-glob-to-any-file: '*.c*'
- any-glob-to-any-file: '*.h'
lang-perl:
- "*.pl"
- "*perl*"
- changed-files:
- any-glob-to-any-file: '*.pl'
- any-glob-to-any-file: '*perl*'
lang-python:
- "*.py"
- changed-files:
- any-glob-to-any-file: '*.py'
lang-shell:
- "*.sh"
- changed-files:
- any-glob-to-any-file: '*.sh'
lang-netlist:
- "*.blif"
- "*.eblif"
- "*.edif"
- "*.vqm"
- changed-files:
- any-glob-to-any-file: '*.blif'
- any-glob-to-any-file: '*.eblif'
- any-glob-to-any-file: '*.edif'
- any-glob-to-any-file: '*.vqm'
lang-make:
- "*.make"
- Makefile
- CMakeLists.txt
- changed-files:
- any-glob-to-any-file: '*.make'
- any-glob-to-any-file: 'Makefile'
- any-glob-to-any-file: 'CMakeLists.txt'

View File

@ -1,13 +1,19 @@
name: Test
# Run CI on push, PR, and weekly.
on:
push:
workflow_dispatch:
pull_request:
push:
branches:
- 'master'
schedule:
- cron: "0 0 * * 0 " # weekly
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
# Environment variables
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
@ -22,7 +28,7 @@ env:
jobs:
change_detect:
name: "Detect code changes"
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
outputs:
# this is output as string, see https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idoutputs
source_modified: ${{ steps.changes.outputs.status_code == '1' }}
@ -31,12 +37,12 @@ jobs:
docker_repo: ${{ steps.changes.outputs.docker_repo }}
steps:
- name: Cancel previous
uses: styfle/cancel-workflow-action@0.9.1
uses: styfle/cancel-workflow-action@0.12.1
with:
access_token: ${{ github.token }}
- name: Checkout OpenFPGA repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
@ -67,7 +73,7 @@ jobs:
needs: change_detect
if: ${{ fromJSON(needs.change_detect.outputs.source_modified) }}
name: ${{ matrix.config.name }}
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
# Note: dependencies are installed in the container. See details about dependency list in docker/Dockerfile.master
# Comment the line out when base image is built again
#container: ghcr.io/${{ needs.change_detect.outputs.docker_repo }}/openfpga-build-${{ matrix.config.cc}}
@ -76,45 +82,53 @@ jobs:
fail-fast: false
matrix:
config:
- name: "Build Compatibility: GCC-8 (Ubuntu 20.04)"
cc: gcc-8
cxx: g++-8
- name: "Build Compatibility: GCC-9 (Ubuntu 20.04)"
- name: "Build Compatibility: GCC-9 (Ubuntu 22.04)"
cc: gcc-9
cxx: g++-9
- name: "Build Compatibility: GCC-10 (Ubuntu 20.04)"
dependency_version: "ubuntu22p04"
- name: "Build Compatibility: GCC-10 (Ubuntu 22.04)"
cc: gcc-10
cxx: g++-10
- name: "Build Compatibility: GCC-11 (Ubuntu 20.04)"
dependency_version: "ubuntu22p04"
- name: "Build Compatibility: GCC-11 (Ubuntu 22.04)"
cc: gcc-11
cxx: g++-11
- name: "Build Compatibility: Clang-6 (Ubuntu 20.04)"
cc: clang-6.0
cxx: clang++-6.0
- name: "Build Compatibility: Clang-7 (Ubuntu 20.04)"
cc: clang-7
cxx: clang++-7
- name: "Build Compatibility: Clang-8 (Ubuntu 20.04)"
cc: clang-8
cxx: clang++-8
- name: "Build Compatibility: Clang-10 (Ubuntu 20.04)"
cc: clang-10
cxx: clang++-10
dependency_version: "ubuntu22p04"
- name: "Build Compatibility: GCC-12 (Ubuntu 22.04)"
cc: gcc-12
cxx: g++-12
dependency_version: "ubuntu22p04"
- name: "Build Compatibility: Clang-11 (Ubuntu 22.04)"
cc: clang-11
cxx: clang++-11
dependency_version: "ubuntu22p04"
- name: "Build Compatibility: Clang-12 (Ubuntu 22.04)"
cc: clang-12
cxx: clang++-12
dependency_version: "ubuntu22p04"
- name: "Build Compatibility: Clang-13 (Ubuntu 22.04)"
cc: clang-13
cxx: clang++-13
dependency_version: "ubuntu22p04"
- name: "Build Compatibility: Clang-14 (Ubuntu 22.04)"
cc: clang-14
cxx: clang++-14
dependency_version: "ubuntu22p04"
# Define the steps to run the build job
env:
CC: ${{ matrix.config.cc }}
CXX: ${{ matrix.config.cxx }}
steps:
- name: Cancel previous
uses: styfle/cancel-workflow-action@0.9.1
uses: styfle/cancel-workflow-action@0.12.1
with:
access_token: ${{ github.token }}
- name: Checkout OpenFPGA repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install dependencies
run: sudo bash ./.github/workflows/install_dependencies_build.sh
run: sudo bash ./.github/workflows/install_dependencies_build_${{ matrix.config.dependency_version }}.sh
- name: Dump tool versions
run: |
@ -129,12 +143,18 @@ jobs:
run: |
make all BUILD_TYPE=$BUILD_TYPE
- name: Clear error log
if: ${{ failure() }}
shell: bash
run: |
make all BUILD_TYPE=$BUILD_TYPE -j1
# Check the cache size and see if it is over the limit
- name: Check ccache size
run: ccache -s
- name: Upload artifact
uses: actions/upload-artifact@v2
if: ${{ matrix.config.cc == 'gcc-9'}}
uses: actions/upload-artifact@v4
if: ${{ matrix.config.cc == 'gcc-11'}}
with:
name: openfpga
path: |
@ -151,11 +171,12 @@ jobs:
openfpga_flow
openfpga.sh
linux_build_opt:
needs: change_detect
if: ${{ fromJSON(needs.change_detect.outputs.source_modified) }}
name: ${{ matrix.config.name }}
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
# Note: dependencies are installed in the container. See details about dependency list in docker/Dockerfile.master
# Comment the line out when base image is built again
#container: ghcr.io/${{ needs.change_detect.outputs.docker_repo }}/openfpga-build-${{ matrix.config.cc}}
@ -164,41 +185,46 @@ jobs:
fail-fast: false
matrix:
config:
- name: "Build w/o Yosys (Ubuntu 20.04)"
cc: gcc-9
cxx: g++-9
- name: "Build w/o Yosys (Ubuntu 22.04)"
cc: gcc-11
cxx: g++-11
cmake_flags: "-DOPENFPGA_WITH_YOSYS=OFF"
- name: "Build w/o Yosys plugin (Ubuntu 20.04)"
cc: gcc-9
cxx: g++-9
dependency_version: "ubuntu22p04"
- name: "Build w/o Yosys plugin (Ubuntu 22.04)"
cc: gcc-11
cxx: g++-11
cmake_flags: "-DOPENFPGA_WITH_YOSYS_PLUGIN=OFF"
- name: "Build w/o test (Ubuntu 20.04)"
cc: gcc-9
cxx: g++-9
dependency_version: "ubuntu22p04"
- name: "Build w/o test (Ubuntu 22.04)"
cc: gcc-11
cxx: g++-11
cmake_flags: "-DOPENFPGA_WITH_TEST=OFF"
- name: "Build w/o version number (Ubuntu 20.04)"
cc: gcc-9
cxx: g++-9
dependency_version: "ubuntu22p04"
- name: "Build w/o version number (Ubuntu 22.04)"
cc: gcc-11
cxx: g++-11
cmake_flags: "-DOPENFPGA_WITH_VERSION=OFF"
- name: "Build w/o SWIG support (Ubuntu 20.04)"
cc: gcc-9
cxx: g++-9
dependency_version: "ubuntu22p04"
- name: "Build w/o SWIG support (Ubuntu 22.04)"
cc: gcc-11
cxx: g++-11
cmake_flags: "-DOPENFPGA_WITH_SWIG=OFF"
dependency_version: "ubuntu22p04"
# Define the steps to run the build job
env:
CC: ${{ matrix.config.cc }}
CXX: ${{ matrix.config.cxx }}
steps:
- name: Cancel previous
uses: styfle/cancel-workflow-action@0.9.1
uses: styfle/cancel-workflow-action@0.12.1
with:
access_token: ${{ github.token }}
- name: Checkout OpenFPGA repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install dependencies
run: sudo bash ./.github/workflows/install_dependencies_build.sh
run: sudo bash ./.github/workflows/install_dependencies_build_${{ matrix.config.dependency_version }}.sh
- name: Dump tool versions
run: |
@ -217,29 +243,34 @@ jobs:
needs: change_detect
if: ${{ fromJSON(needs.change_detect.outputs.source_modified) }}
name: ${{ matrix.config.name }}
runs-on: ubuntu-22.04
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
config:
- name: "Build (Ubuntu 22.04)"
- name: "Build (GCC-11 on Ubuntu 20.04)"
cc: gcc-11
cxx: g++-11
dependency_version: "ubuntu20p04"
- name: "Build (Clang-10 on Ubuntu 20.04)"
cc: clang-10
cxx: clang++-10
dependency_version: "ubuntu20p04"
# Define the steps to run the build job
env:
CC: ${{ matrix.config.cc }}
CXX: ${{ matrix.config.cxx }}
steps:
- name: Cancel previous
uses: styfle/cancel-workflow-action@0.9.1
uses: styfle/cancel-workflow-action@0.12.1
with:
access_token: ${{ github.token }}
- name: Checkout OpenFPGA repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install dependencies
run: sudo bash ./.github/workflows/install_dependencies_build_ubuntu22p04.sh
run: sudo bash ./.github/workflows/install_dependencies_build_${{ matrix.config.dependency_version }}.sh
- name: Dump tool versions
run: |
@ -270,23 +301,24 @@ jobs:
cxx: g++-11
build_type: debug
cores: 4
dependency_version: "ubuntu22p04"
# Define the steps to run the build job
env:
CC: ${{ matrix.config.cc }}
CXX: ${{ matrix.config.cxx }}
steps:
- name: Cancel previous
uses: styfle/cancel-workflow-action@0.9.1
uses: styfle/cancel-workflow-action@0.12.1
with:
access_token: ${{ github.token }}
- name: Checkout OpenFPGA repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo bash ./.github/workflows/install_dependencies_build_ubuntu22p04.sh
sudo bash ./.github/workflows/install_dependencies_run_ubuntu22p04.sh
sudo bash ./.github/workflows/install_dependencies_build_${{ matrix.config.dependency_version }}.sh
sudo bash ./.github/workflows/install_dependencies_run_${{ matrix.config.dependency_version }}.sh
sudo python3 -m pip install -r requirements.txt
- name: Dump tool versions
@ -321,23 +353,24 @@ jobs:
cxx: g++-11
build_type: release
cores: 4
dependency_version: "ubuntu22p04"
# Define the steps to run the build job
env:
CC: ${{ matrix.config.cc }}
CXX: ${{ matrix.config.cxx }}
steps:
- name: Cancel previous
uses: styfle/cancel-workflow-action@0.9.1
uses: styfle/cancel-workflow-action@0.12.1
with:
access_token: ${{ github.token }}
- name: Checkout OpenFPGA repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo bash ./.github/workflows/install_dependencies_build_ubuntu22p04.sh
sudo bash ./.github/workflows/install_dependencies_run_ubuntu22p04.sh
sudo bash ./.github/workflows/install_dependencies_build_${{ matrix.config.dependency_version }}.sh
sudo bash ./.github/workflows/install_dependencies_run_${{ matrix.config.dependency_version }}.sh
sudo python3 -m pip install -r requirements.txt
- name: Dump tool versions
@ -360,18 +393,18 @@ jobs:
docker_distribution:
name: Build docker image for distribution
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
needs: [linux_build, change_detect]
steps:
- name: Cancel previous
uses: styfle/cancel-workflow-action@0.9.1
uses: styfle/cancel-workflow-action@0.12.1
with:
access_token: ${{ github.token }}
- name: Checkout OpenFPGA repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Download a built artifacts
uses: actions/download-artifact@v2
uses: actions/download-artifact@v4
with:
name: openfpga
- name: Set up QEMU
@ -397,7 +430,7 @@ jobs:
linux_regression_tests:
name: linux_regression_tests
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
needs: [linux_build, change_detect]
container: ghcr.io/${{ needs.change_detect.outputs.docker_repo }}/openfpga-env
strategy:
@ -417,14 +450,14 @@ jobs:
- name: tcl_reg_test
steps:
- name: Cancel previous
uses: styfle/cancel-workflow-action@0.9.1
uses: styfle/cancel-workflow-action@0.12.1
with:
access_token: ${{ github.token }}
- name: Checkout OpenFPGA repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Download a built artifacts
uses: actions/download-artifact@v2
uses: actions/download-artifact@v4
with:
name: openfpga
- name: chmod
@ -438,11 +471,11 @@ jobs:
chmod +x build/yosys/bin/yosys-config
chmod +x build/yosys/bin/yosys-filterlib
chmod +x build/yosys/bin/yosys-smtbmc
- name: ${{matrix.config.name}}_GCC-9_(Ubuntu 20.04)
- name: ${{matrix.config.name}}_GCC-11_(Ubuntu 22.04)
shell: bash
run: source openfpga.sh && source openfpga_flow/regression_test_scripts/${{matrix.config.name}}.sh --debug --show_thread_logs
- name: Upload artifact
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
if: ${{ failure() }}
with:
name: failed_${{matrix.config.name}}_regression_log
@ -454,7 +487,7 @@ jobs:
needs: change_detect
if: ${{ !fromJSON(needs.change_detect.outputs.source_modified) }}
name: docker_regression_tests
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
container:
image: ghcr.io/${{ needs.change_detect.outputs.docker_repo }}/openfpga-master:latest
options: --user root --workdir /home/openfpga_user
@ -475,23 +508,23 @@ jobs:
- name: tcl_reg_test
steps:
- name: Cancel previous
uses: styfle/cancel-workflow-action@0.9.1
uses: styfle/cancel-workflow-action@0.12.1
with:
access_token: ${{ github.token }}
- name: Checkout OpenFPGA repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: ${{matrix.config.name}}_GCC-9_(Ubuntu 20.04)
- name: ${{matrix.config.name}}_GCC-11_(Ubuntu 22.04)
shell: bash
run: |
bash .github/workflows/install_dependencies_run.sh
bash .github/workflows/install_dependencies_run_ubuntu22p04.sh
${PYTHON_EXEC} -m pip install -r requirements.txt
rsync -am --exclude='openfpga_flow/**' /opt/openfpga/. .
unset OPENFPGA_PATH
source openfpga.sh && source openfpga_flow/regression_test_scripts/${{matrix.config.name}}.sh --debug --show_thread_logs
- name: Upload artifact
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
if: ${{ failure() }}
with:
name: failed_${{matrix.config.name}}_regression_log

View File

@ -1,13 +1,19 @@
name: Cell Library Tests
# Run CI on push, PR, and weekly.
on:
push:
workflow_dispatch:
pull_request:
push:
branches:
- 'master'
schedule:
- cron: "0 0 * * 0 " # weekly
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
# Multiple job to tests
jobs:
# Test the RTL compilation compatibility
@ -16,7 +22,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Cancel previous
uses: styfle/cancel-workflow-action@0.9.1
uses: styfle/cancel-workflow-action@0.12.1
with:
access_token: ${{ github.token }}

View File

@ -7,10 +7,14 @@ env:
DOCKER_REPO: ${{ secrets.DOCKER_REPO }}
REPO_OWNER: ${{ github.repository_owner }}
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
change_detect:
name: "Detect code changes"
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
outputs:
docker_repo: ${{ steps.changes.outputs.docker_repo }}
steps:
@ -31,7 +35,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
@ -64,18 +68,17 @@ jobs:
strategy:
matrix:
compiler:
- gcc-7
- gcc-8
- gcc-9
- gcc-10
- gcc-11
- clang-6.0
- clang-7
- clang-8
- clang-10
- gcc-12
- clang-11
- clang-12
- clang-13
- clang-14
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx

View File

@ -3,29 +3,39 @@ name: Code Format
# Run CI on push, PR, and weekly.
on:
push:
workflow_dispatch:
pull_request:
push:
branches:
- 'master'
schedule:
- cron: "0 0 * * 0 " # weekly
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
# Multiple job to tests
jobs:
change_detect:
name: "Check"
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
config:
- name: "C/C++"
code_type: "-cpp"
dependency_version: "ubuntu22p04"
- name: "XML"
code_type: "-xml"
dependency_version: "ubuntu22p04"
- name: "Python"
code_type: "-py"
dependency_version: "ubuntu22p04"
steps:
- name: Cancel previous
uses: styfle/cancel-workflow-action@0.9.1
uses: styfle/cancel-workflow-action@0.12.1
with:
access_token: ${{ github.token }}
@ -34,12 +44,12 @@ jobs:
- name: Install dependencies
run: |
sudo bash ./.github/workflows/install_dependencies_build.sh
sudo bash ./.github/workflows/install_dependencies_build_${{ matrix.config.dependency_version }}.sh
sudo python3 -m pip install -r requirements.txt
- name: Dump tool versions
run: |
clang-format-10 --version
clang-format-14 --version
black --version
- name: Check format

View File

@ -53,6 +53,9 @@ apt-get install -y \
gcc-10 \
g++-11 \
gcc-11 \
clang-11 \
clang-12 \
clang-format-12 \
clang-13 \
clang-14 \
clang-format-14 \
libxml2-utils

View File

@ -4,9 +4,12 @@ on:
jobs:
triage:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@main
- uses: actions/labeler@v5
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
configuration-path: ".github/labeler.yml"

View File

@ -1,8 +1,9 @@
name: Count Patches
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * *'
push:
branches:
- 'master'
env:
TAG_COMMIT: 8ee3fb8..
@ -41,6 +42,7 @@ jobs:
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{env.BRANCH_NAME}}
force: true
- name: Create Auto PR
if: "!contains(steps.log.outputs.message, 'Updated Patch Count') && contains(steps.repo.outputs.message, 'lnis-uofu/OpenFPGA')"

View File

@ -17,7 +17,9 @@ sphinx:
configuration: docs/source/conf.py
# Optionally build your docs in additional formats such as PDF and ePub
formats: all
formats:
- pdf
- epub
# Optionally set the version of Python and requirements required to build your docs
python:

View File

@ -321,6 +321,8 @@ if (OPENFPGA_WITH_YOSYS)
# run makefile provided, we pass-on the options to the local make file
add_custom_target(
yosys ALL
# add step to remove the 'built-in' quicklogic plugins code in yosys
COMMAND rm -rf techlibs/quicklogic
COMMAND $(MAKE) config-gcc
COMMAND $(MAKE) install PREFIX=${CMAKE_CURRENT_BINARY_DIR}/yosys/
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/yosys

View File

@ -42,7 +42,7 @@ endif
# Define executables
PYTHON_EXEC ?= python3
CLANG_FORMAT_EXEC ?= clang-format-10
CLANG_FORMAT_EXEC ?= clang-format-14
XML_FORMAT_EXEC ?= xmllint
PYTHON_FORMAT_EXEC ?= black

View File

@ -11,16 +11,19 @@ Version: see [`VERSION.md`](VERSION.md)
The award-winning OpenFPGA framework is the **first open-source FPGA IP generator with silicon proofs** supporting highly-customizable FPGA architectures. OpenFPGA provides complete EDA support for customized FPGAs, including Verilog-to-bitstream generation and self-testing verification. OpenFPGA opens the door to democratizing FPGA technology and EDA techniques with agile prototyping approaches and constantly evolving EDA tools for chip designers and researchers.
**If this is your first time working with OpenFPGA, we strongly **recommend you watch the** [introduction video about OpenFPGA](https://youtu.be/ocODUGcYGqo)**
> [!TIP]
> If this is your first time working with OpenFPGA, we strongly recommend you watch the [introduction video about OpenFPGA](https://youtu.be/ocODUGcYGqo)
A quick overview of OpenFPGA tools can be found [**here**](https://openfpga.readthedocs.io/en/master/tutorials/getting_started/tools/).
We also recommend potential users check out the summary of [**technical capabilities**](https://openfpga.readthedocs.io/en/master/overview/tech_highlights/#) before compiling.
**Before asking for help, please checkout the** [Frequently Asked Questions](https://github.com/lnis-uofu/OpenFPGA/discussions/937)
> [!TIP]
> Before asking for help, please checkout the [Frequently Asked Questions](https://github.com/lnis-uofu/OpenFPGA/discussions/937)
## Compilation
**A tutorial **video about **how to compile** can be** found [here](https://youtu.be/F9sMRmDewM0)**
> [!NOTE]
> A tutorial video about how to compile can be found [here](https://youtu.be/F9sMRmDewM0)
Detailed guidelines are available at [**compilation guidelines**](https://openfpga.readthedocs.io/en/master/tutorials/getting_started/compile/).
Before starting, we strongly recommend you read the required dependencies and ensure that they are correctly installed.
@ -36,7 +39,7 @@ You can find a set of [tutorials](https://openfpga.readthedocs.io/en/master/tuto
## Backward Compatibility
If you were using an old version of OpenFPGA and are now interested to move to the latest version, please check out the [developer guidelines](https://openfpga.readthedocs.io/en/master/dev_manual/back_compatibile).
If you were using an old version of OpenFPGA and are now interested to move to the latest version, please check out the [developer guidelines](https://openfpga.readthedocs.io/en/master/dev_manual/back_compatible/).
## License
@ -54,8 +57,8 @@ Bibtex:
@ARTICLE{9098028, author={Tang, Xifan and Giacomin, Edouard and Chauviere, Baudouin and Alacchi, Aurélien and Gaillardon, Pierre-Emmanuel}, journal={IEEE Micro}, title={OpenFPGA: An Open-Source Framework for Agile Prototyping Customizable FPGAs}, year={2020}, volume={40}, number={4}, pages={41-48}, doi={10.1109/MM.2020.2995854}}
```
A list of related publications can be found [here](https://openfpga.readthedocs.io/en/master/reference/).
A list of related publications can be found [here](https://openfpga.readthedocs.io/en/master/appendix/reference/).
## Contributing to OpenFPGA
Please read the [contributor guidelines](https://openfpga.readthedocs.io/en/master/dev_manual/contributor_guide) if you would like to contribute to OpenFPGA.
Please read the [contributor guidelines](https://openfpga.readthedocs.io/en/master/dev_manual/contributor_guide/) if you would like to contribute to OpenFPGA.

View File

@ -1 +1 @@
1.2.1795
1.2.2938

View File

@ -1,303 +0,0 @@
# The MIT License (MIT)
#
# Copyright (c) 2015 Justus Calvin
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# FindTBB
# -------
#
# Find TBB include directories and libraries.
#
# Usage:
#
# find_package(TBB [major[.minor]] [EXACT]
# [QUIET] [REQUIRED]
# [[COMPONENTS] [components...]]
# [OPTIONAL_COMPONENTS components...])
#
# where the allowed components are tbbmalloc and tbb_preview. Users may modify
# the behavior of this module with the following variables:
#
# * TBB_ROOT_DIR - The base directory the of TBB installation.
# * TBB_INCLUDE_DIR - The directory that contains the TBB headers files.
# * TBB_LIBRARY - The directory that contains the TBB library files.
# * TBB_<library>_LIBRARY - The path of the TBB the corresponding TBB library.
# These libraries, if specified, override the
# corresponding library search results, where <library>
# may be tbb, tbb_debug, tbbmalloc, tbbmalloc_debug,
# tbb_preview, or tbb_preview_debug.
# * TBB_USE_DEBUG_BUILD - The debug version of tbb libraries, if present, will
# be used instead of the release version.
#
# Users may modify the behavior of this module with the following environment
# variables:
#
# * TBB_INSTALL_DIR
# * TBBROOT
# * LIBRARY_PATH
#
# This module will set the following variables:
#
# * TBB_FOUND - Set to false, or undefined, if we havent found, or
# dont want to use TBB.
# * TBB_<component>_FOUND - If False, optional <component> part of TBB sytem is
# not available.
# * TBB_VERSION - The full version string
# * TBB_VERSION_MAJOR - The major version
# * TBB_VERSION_MINOR - The minor version
# * TBB_INTERFACE_VERSION - The interface version number defined in
# tbb/tbb_stddef.h.
# * TBB_<library>_LIBRARY_RELEASE - The path of the TBB release version of
# <library>, where <library> may be tbb, tbb_debug,
# tbbmalloc, tbbmalloc_debug, tbb_preview, or
# tbb_preview_debug.
# * TBB_<library>_LIBRARY_DEGUG - The path of the TBB release version of
# <library>, where <library> may be tbb, tbb_debug,
# tbbmalloc, tbbmalloc_debug, tbb_preview, or
# tbb_preview_debug.
#
# The following varibles should be used to build and link with TBB:
#
# * TBB_INCLUDE_DIRS - The include directory for TBB.
# * TBB_LIBRARIES - The libraries to link against to use TBB.
# * TBB_LIBRARIES_RELEASE - The release libraries to link against to use TBB.
# * TBB_LIBRARIES_DEBUG - The debug libraries to link against to use TBB.
# * TBB_DEFINITIONS - Definitions to use when compiling code that uses
# TBB.
# * TBB_DEFINITIONS_RELEASE - Definitions to use when compiling release code that
# uses TBB.
# * TBB_DEFINITIONS_DEBUG - Definitions to use when compiling debug code that
# uses TBB.
#
# This module will also create the "tbb" target that may be used when building
# executables and libraries.
include(FindPackageHandleStandardArgs)
if(NOT TBB_FOUND)
##################################
# Check the build type
##################################
if(NOT DEFINED TBB_USE_DEBUG_BUILD)
if(CMAKE_BUILD_TYPE MATCHES "(Debug|DEBUG|debug|RelWithDebInfo|RELWITHDEBINFO|relwithdebinfo)")
set(TBB_BUILD_TYPE DEBUG)
else()
set(TBB_BUILD_TYPE RELEASE)
endif()
elseif(TBB_USE_DEBUG_BUILD)
set(TBB_BUILD_TYPE DEBUG)
else()
set(TBB_BUILD_TYPE RELEASE)
endif()
##################################
# Set the TBB search directories
##################################
# Define search paths based on user input and environment variables
set(TBB_SEARCH_DIR ${TBB_ROOT_DIR} $ENV{TBB_INSTALL_DIR} $ENV{TBBROOT})
# Define the search directories based on the current platform
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(TBB_DEFAULT_SEARCH_DIR "C:/Program Files/Intel/TBB"
"C:/Program Files (x86)/Intel/TBB")
# Set the target architecture
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(TBB_ARCHITECTURE "intel64")
else()
set(TBB_ARCHITECTURE "ia32")
endif()
# Set the TBB search library path search suffix based on the version of VC
if(WINDOWS_STORE)
set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc11_ui")
elseif(MSVC14)
set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc14")
elseif(MSVC12)
set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc12")
elseif(MSVC11)
set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc11")
elseif(MSVC10)
set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc10")
endif()
# Add the library path search suffix for the VC independent version of TBB
list(APPEND TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc_mt")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
# OS X
set(TBB_DEFAULT_SEARCH_DIR "/opt/intel/tbb")
# TODO: Check to see which C++ library is being used by the compiler.
if(NOT ${CMAKE_SYSTEM_VERSION} VERSION_LESS 13.0)
# The default C++ library on OS X 10.9 and later is libc++
set(TBB_LIB_PATH_SUFFIX "lib/libc++" "lib")
else()
set(TBB_LIB_PATH_SUFFIX "lib")
endif()
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
# Linux
set(TBB_DEFAULT_SEARCH_DIR "/opt/intel/tbb")
# TODO: Check compiler version to see the suffix should be <arch>/gcc4.1 or
# <arch>/gcc4.1. For now, assume that the compiler is more recent than
# gcc 4.4.x or later.
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
set(TBB_LIB_PATH_SUFFIX "lib/intel64/gcc4.4")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^i.86$")
set(TBB_LIB_PATH_SUFFIX "lib/ia32/gcc4.4")
endif()
endif()
##################################
# Find the TBB include dir
##################################
find_path(TBB_INCLUDE_DIRS tbb/tbb.h
HINTS ${TBB_INCLUDE_DIR} ${TBB_SEARCH_DIR}
PATHS ${TBB_DEFAULT_SEARCH_DIR}
PATH_SUFFIXES include)
##################################
# Set version strings
##################################
if(TBB_INCLUDE_DIRS)
file(READ "${TBB_INCLUDE_DIRS}/tbb/tbb_stddef.h" _tbb_version_file)
string(REGEX REPLACE ".*#define TBB_VERSION_MAJOR ([0-9]+).*" "\\1"
TBB_VERSION_MAJOR "${_tbb_version_file}")
string(REGEX REPLACE ".*#define TBB_VERSION_MINOR ([0-9]+).*" "\\1"
TBB_VERSION_MINOR "${_tbb_version_file}")
string(REGEX REPLACE ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1"
TBB_INTERFACE_VERSION "${_tbb_version_file}")
set(TBB_VERSION "${TBB_VERSION_MAJOR}.${TBB_VERSION_MINOR}")
endif()
##################################
# Find TBB components
##################################
if(TBB_VERSION VERSION_LESS 4.3)
set(TBB_SEARCH_COMPOMPONENTS tbb_preview tbbmalloc tbb)
else()
set(TBB_SEARCH_COMPOMPONENTS tbb_preview tbbmalloc_proxy tbbmalloc tbb)
endif()
# Find each component
foreach(_comp ${TBB_SEARCH_COMPOMPONENTS})
if(";${TBB_FIND_COMPONENTS};tbb;" MATCHES ";${_comp};")
# Search for the libraries
find_library(TBB_${_comp}_LIBRARY_RELEASE ${_comp}
HINTS ${TBB_LIBRARY} ${TBB_SEARCH_DIR}
PATHS ${TBB_DEFAULT_SEARCH_DIR} ENV LIBRARY_PATH
PATH_SUFFIXES ${TBB_LIB_PATH_SUFFIX})
find_library(TBB_${_comp}_LIBRARY_DEBUG ${_comp}_debug
HINTS ${TBB_LIBRARY} ${TBB_SEARCH_DIR}
PATHS ${TBB_DEFAULT_SEARCH_DIR} ENV LIBRARY_PATH
PATH_SUFFIXES ${TBB_LIB_PATH_SUFFIX})
if(TBB_${_comp}_LIBRARY_DEBUG)
list(APPEND TBB_LIBRARIES_DEBUG "${TBB_${_comp}_LIBRARY_DEBUG}")
endif()
if(TBB_${_comp}_LIBRARY_RELEASE)
list(APPEND TBB_LIBRARIES_RELEASE "${TBB_${_comp}_LIBRARY_RELEASE}")
endif()
if(TBB_${_comp}_LIBRARY_${TBB_BUILD_TYPE} AND NOT TBB_${_comp}_LIBRARY)
set(TBB_${_comp}_LIBRARY "${TBB_${_comp}_LIBRARY_${TBB_BUILD_TYPE}}")
endif()
if(TBB_${_comp}_LIBRARY AND EXISTS "${TBB_${_comp}_LIBRARY}")
set(TBB_${_comp}_FOUND TRUE)
else()
set(TBB_${_comp}_FOUND FALSE)
endif()
# Mark internal variables as advanced
mark_as_advanced(TBB_${_comp}_LIBRARY_RELEASE)
mark_as_advanced(TBB_${_comp}_LIBRARY_DEBUG)
mark_as_advanced(TBB_${_comp}_LIBRARY)
endif()
endforeach()
##################################
# Set compile flags and libraries
##################################
set(TBB_DEFINITIONS_RELEASE "")
set(TBB_DEFINITIONS_DEBUG "-DTBB_USE_DEBUG=1")
if(TBB_LIBRARIES_${TBB_BUILD_TYPE})
set(TBB_DEFINITIONS "${TBB_DEFINITIONS_${TBB_BUILD_TYPE}}")
set(TBB_LIBRARIES "${TBB_LIBRARIES_${TBB_BUILD_TYPE}}")
elseif(TBB_LIBRARIES_RELEASE)
set(TBB_DEFINITIONS "${TBB_DEFINITIONS_RELEASE}")
set(TBB_LIBRARIES "${TBB_LIBRARIES_RELEASE}")
elseif(TBB_LIBRARIES_DEBUG)
set(TBB_DEFINITIONS "${TBB_DEFINITIONS_DEBUG}")
set(TBB_LIBRARIES "${TBB_LIBRARIES_DEBUG}")
endif()
find_package_handle_standard_args(TBB
REQUIRED_VARS TBB_INCLUDE_DIRS TBB_LIBRARIES
HANDLE_COMPONENTS
VERSION_VAR TBB_VERSION)
##################################
# Create targets
##################################
if(NOT CMAKE_VERSION VERSION_LESS 3.0 AND TBB_FOUND)
add_library(tbb SHARED IMPORTED)
set_target_properties(tbb PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES ${TBB_INCLUDE_DIRS}
IMPORTED_LOCATION ${TBB_LIBRARIES})
if(TBB_LIBRARIES_RELEASE AND TBB_LIBRARIES_DEBUG)
set_target_properties(tbb PROPERTIES
INTERFACE_COMPILE_DEFINITIONS "$<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:TBB_USE_DEBUG=1>"
IMPORTED_LOCATION_DEBUG ${TBB_LIBRARIES_DEBUG}
IMPORTED_LOCATION_RELWITHDEBINFO ${TBB_LIBRARIES_DEBUG}
IMPORTED_LOCATION_RELEASE ${TBB_LIBRARIES_RELEASE}
IMPORTED_LOCATION_MINSIZEREL ${TBB_LIBRARIES_RELEASE}
)
elseif(TBB_LIBRARIES_RELEASE)
set_target_properties(tbb PROPERTIES IMPORTED_LOCATION ${TBB_LIBRARIES_RELEASE})
else()
set_target_properties(tbb PROPERTIES
INTERFACE_COMPILE_DEFINITIONS "${TBB_DEFINITIONS_DEBUG}"
IMPORTED_LOCATION ${TBB_LIBRARIES_DEBUG}
)
endif()
endif()
mark_as_advanced(TBB_INCLUDE_DIRS TBB_LIBRARIES)
unset(TBB_ARCHITECTURE)
unset(TBB_BUILD_TYPE)
unset(TBB_LIB_PATH_SUFFIX)
unset(TBB_DEFAULT_SEARCH_DIR)
endif()

View File

@ -1,9 +1,9 @@
FROM ubuntu:20.04
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install software-properties-common -y
# 18.04 includes 2.17 but github requires 2.18+ to support submodules.
RUN add-apt-repository ppa:git-core/ppa
ADD .github/workflows/install_dependencies_build.sh install_dependencies_build.sh
ADD .github/workflows/install_dependencies_build_ubuntu22p04.sh install_dependencies_build.sh
RUN bash install_dependencies_build.sh
ADD requirements.txt requirements.txt
RUN python3 -m pip install -r requirements.txt

View File

@ -1,2 +0,0 @@
FROM ghcr.io/lnis-uofu/openfpga-build-base
RUN apt-get update && apt-get install -y clang-format-7 clang-10

View File

@ -0,0 +1,2 @@
FROM ghcr.io/lnis-uofu/openfpga-build-base
RUN apt-get update && apt-get install -y clang-format-14 clang-11

View File

@ -0,0 +1,2 @@
FROM ghcr.io/lnis-uofu/openfpga-build-base
RUN apt-get update && apt-get install -y clang-format-14 clang-12

View File

@ -0,0 +1,2 @@
FROM ghcr.io/lnis-uofu/openfpga-build-base
RUN apt-get update && apt-get install -y clang-format-14 clang-13

View File

@ -0,0 +1,2 @@
FROM ghcr.io/lnis-uofu/openfpga-build-base
RUN apt-get update && apt-get install -y clang-format-14 clang-14

View File

@ -1,2 +0,0 @@
FROM ghcr.io/lnis-uofu/openfpga-build-base
RUN apt-get update && apt-get install -y clang-format-7 clang-6.0

View File

@ -1,2 +0,0 @@
FROM ghcr.io/lnis-uofu/openfpga-build-base
RUN apt-get update && apt-get install -y clang-format-7 clang-7

View File

@ -1,2 +0,0 @@
FROM ghcr.io/lnis-uofu/openfpga-build-base
RUN apt-get update && apt-get install -y clang-format-7 clang-8

View File

@ -1,15 +1,13 @@
FROM ubuntu:20.04
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install --no-install-recommends software-properties-common -y
# 18.04 includes 2.17 but github requires 2.18+ to support submodules.
#RUN add-apt-repository ppa:git-core/ppa
ADD .github/workflows/install_dependencies_run.sh install_dependencies_run.sh
ADD .github/workflows/install_dependencies_run_ubuntu22p04.sh install_dependencies_run.sh
RUN bash install_dependencies_run.sh
RUN curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
RUN python3.8 get-pip.py && rm get-pip.py
RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.8 2
# Comment out this line since Ubuntu 20.04 does not support it
# RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 1
RUN python3.10 get-pip.py && rm get-pip.py
RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.10 2
ADD requirements.txt requirements.txt
ENV PYTHON_EXEC=python3.8
ENV PYTHON_EXEC=python3.10
RUN ${PYTHON_EXEC} -m pip install -r requirements.txt

2
docker/Dockerfile.gcc-12 Normal file
View File

@ -0,0 +1,2 @@
FROM ghcr.io/lnis-uofu/openfpga-build-base
RUN add-apt-repository -y ppa:ubuntu-toolchain-r/test && apt-get update && apt-get install -y gcc-12 g++-12

View File

@ -1,2 +0,0 @@
FROM ghcr.io/lnis-uofu/openfpga-build-base
RUN apt-get update && apt-get install -y gcc-7 g++-7

View File

@ -1,2 +0,0 @@
FROM ghcr.io/lnis-uofu/openfpga-build-base
RUN apt-get update && apt-get install -y gcc-8 g++-8

View File

@ -1,4 +1,64 @@
.. dev_manual_cicd_setup::
.. _developer_ci:
Continous Integration
=====================
Motivation
----------
Continous Integration (CI) systems are built to ensure that input and output files of each teams are
- Correct
- Reproducable
- Consistent with other teams
CI system is automatically triggered on
- Main branch: the master branch of the codebase
- A pull request on main branch
Workflows
---------
Principles
^^^^^^^^^^
Continous Integration system consists a number of workflows, each of which is designed to validate a specific aspect of the codebase.
For the work of each team, there is at least 1 dedicated workflow.
Workflows can categorized in two types
.. option:: Generation flow
Such type of workflow is designed to ensure that golden files (netlists, bitstreams, etc.) are reproduciable.
A generation workflow consists of three steps:
- Detect changes on input files, e.g., architecture files, IPs and related scripts.
- If no changes detected, the workflow ends, since the golden outputs are not changed in a pull request
- If any changes are detected, the workflow will continue to the next steps
- Regenerate golden files by calling scripts. By the end of this step, it will compare the newly generated files with the golden reference (current branch)
- If there are no changes, the workflow ends.
- If any changes on golden reference are detected, this will error out. It means that the current golden reference are not reproduciable.
.. warning:: If any changes on golden references are detected, code review has to be enforced. Ensure that all the teams impacted agree on the changes.
.. option:: Validation flow
Such type of workflow is designed to verify the correctness of golden files
A validation workflow consists of three steps:
- Detect changes on golden reference (some pull requests update golden references)
- If no changes detected, the workflow ends. There is no need to validate the correctness of the golden reference (previous pull request should already do so).
- If any changes are detected, the workflow will continue to the next steps
- Run validation by calling scripts. For example, verification may call HDL simulations to verify the correctness of netlists.
- If the new golden reference passes all the tests, this will end.
- If the new golden reference fails any test, this will error out. It means that the current golden reference can not meet basic requirements.
.. warning:: If any validation flow failed, the pull request cannot be merged in general.
CI/CD setup
-----------

View File

@ -0,0 +1,44 @@
.. _developer_contributor_guidelines_general_rules:
General Rules
=============
Motivation
----------
Github projects involve many parties with different interests.
It is necessary to establish rules to
- guarantee the quality of each pull request by establishing a standard
- code review for each pull request is straightforward
- contributors have confidence when submitting changes
Create Pull requests
--------------------
- Contributors should state clearly their motivation and the principles of code changes in each pull request
- Contributors should be active in resolving conflicts with other contributors as well as maintainers. In principle, all the maintainers want every pull request in and are looking for reasons to approve it.
- Each pull request should pass all the existing tests in CI (See :ref:`developer_contributor_guidelines_checkin_system` for details). Otherwise, it should not be merged unless you get a waiver from all the maintainers.
- Contributors should not modify any codes/tests which are unrelated to the scope of their pull requests.
- The size of each pull request should be small. Large pull request takes weeks to be merged. The recommend size of pull request is up to 500 lines of codes changes. If you have one large file, this can be waived. However, the number of files to be changed should be as small as possible.
.. note:: For large pull requests, it is strongly recommended that contributors should talk to maintainers first or create an issue on the Github. Contributors should clearly define the motivation, detailed technical plan as well as deliverables. Through discussions, the technical plan may be requested to change. Please do not start code changes blindly before the technical plan is approved.
- For any new feature/functionality to be added, there should be
- Dedicated test cases in CI which validates its correctness
- An update on the documentation, if it changes user interface
- Provide sufficient code comments to ease the maintenance
.. _developer_contributor_guidelines_checkin_system:
Check-in System
---------------
.. seealso:: The check-in system is based on continous integration (CI). See details in :ref:`developer_ci`
The check-in system aims to offer a standardized way to
- ensure quailty of each contribution
- resolve conflicts between teams
It is designed for efficient communication between teams.

View File

@ -0,0 +1,11 @@
.. _developer_contributor_guidelines:
Contributor Guidelines
======================
.. toctree::
:maxdepth: 2
general_rules
naming_convention

View File

@ -0,0 +1,224 @@
.. _developer_naming_convention:
Naming Convention
=================
.. _developer_naming_convention_cell_names:
Cell Names
----------
.. warning:: This is a different concept than the cell names in :ref:`developer_naming_convention_ff_model_names`!
.. note:: we refer to standard cell wrapper here. Wrappers are built to make netlists portable between PDKs as well as across standard cell libraries in a PDK.
For code readability, the cell name should follow the convention
::
<Cell_Function><Set_Features><Reset_Features><Output_Features><Drive_Strength>_<Wrapper>
.. option:: Cell_Function
Name of logic function, e.g., AND2, XNOR3, etc.
.. option:: Set_Features
This is mainly for sequential cells, e.g., D-type flip-flops. If a cell contains a set signal, its existence and polarity must be inferreable by the cell name. The available options are
- S: Asynchronous active-high set
- SYNS: Synchronous active-hight set
- SN: Asynchronous active-low set
- SYNSN: Synchronous active-low set
.. note:: For cells without set, this keyword should be empty
.. option:: Reset_Features
This is mainly for sequential cells, e.g., D-type flip-flops. If a cell contains a reset signal, its existence and polarity must be inferreable by the cell name. The available options are
- R: Asynchronous active-high reset
- SYNR: Synchronous active-hight reset
- RN: Asynchronous active-low reset
- SYNRN: Synchronous active-low reset
.. note:: For cells without reset, this keyword should be empty
.. option:: Output_Features
This is mainly for sequential cells, e.g., D-type flip-flops.
- If not specified, the sequential cell contains a pair of differential outputs, e.g., ``Q`` and ``QN``
- If specified, the sequential cell only contains single output, e.g., ``Q``
The available options are
- Q: single output which is positive
- QN: single ouput which is negative
.. note:: For cells without reset, this keyword should be empty
.. option:: Drive_Strength
This is to specify the drive strength of a cell
- If not specified, we assume minimum drive strength, i.e., ``D0``.
- If specified, we expect a format of ``D<int>``, where the integer indicates the drive strength
.. option:: Wrapper
This is to specify if the cell is a wrapper of an existing standard cell
- If not specified, we assume this cell contains RTL
- If specified, we assume this cell is a wrapper of an existing standard cell
A quick example
::
NAND2D4_WRAPPER
represents a wrapper for a standard cell that is a 2-input NAND gate with a drive strength of 4
Another example
::
SDFFSSYNRNQ
represents a scan-chain flip-flop which contains
- Asynchronous active-high set
- Synchronous active-low reset
- Single output
Pin Names
---------
.. note:: Please use lowercase as much as you can
For code readability, the pin name should follow the convention
::
<Pin_Name>_<Polarity><Direction>
.. option:: Pin_Name
Represents the pin name
.. option:: Polarity
Represents polarity of the pin, it can be
- ``n`` denotes a negative-enable (active_low) signal
.. note:: When not specified, by default we assume this is a postive-enable (active-high) signal
.. option:: Direction
Represents the direction of a pin, it can be
- ``i`` denotes an input signal
- ``o`` denotes an output signal
A quick example
::
clk_ni
represents an input clock signal which is negative-enable
Another example
::
q_no
represents an output Q signal which is negative to the input
.. _developer_naming_convention_ff_model_names:
Flip-flop Model Names
---------------------
.. warning:: This is a different concept than the cell names in :ref:`developer_naming_convention_cell_names`!
.. note:: we refer to virtual cell model (used by VPR and Yosys for cell mapping) here.
For code readability, D-type flip-flop model names should follow the convention
::
<Sync_Type>dff<Trigger_Type><Set_Type><Reset_Type>
.. option:: Sync_Features
Represents if the reset/set is synchronous or asynchronous to the clock, it can be
- ``s`` denotes a synchronous behavior
- an empty string "" denotes an asynchronous behavior, e.g., ``ffr``
.. option:: Trigger_Type
Represents if the flip-flop is triggered by rising edge or falling edge of a clock, it can be
- ``n`` means triggered by failling edge
- an empty string "" means triggered by rising edge, e.g., ``ff``
.. option:: Set_Type
Represents if the flip-flop has a set and the polarity of the set, it can be
- ``s`` means that the flip-flop has an active-high set pin
- ``sn`` means that the flip-flop has an active-low set pin
- an empty string "" means the flip-flop does not have a set pin, e.g., ``ff``
.. option:: Reset_Type
Represents if the flip-flop has a reset and the polarity of the reset, it can be
- ``r`` means that the flip-flop has an active-high reset pin
- ``rn`` means that the flip-flop has an active-low reset pin
- an empty string "" means the flip-flop does not have a reset pin, e.g., ``ff``
A quick example
::
ffnrn
represents a flip-flop
- triggered by falling edge
- with an asynchronous active-low reset
Another example
::
sffs
represents a flip-flop
- triggered by rising edge
- with a synchronous active-high set
.. _developer_naming_convention_mux_model_names:
Multiplexer Model Names
-----------------------
.. warning:: This is a different concept than the cell names in :ref:`developer_naming_convention_cell_names`!
.. note:: Here, we refer to the circuit model name used in OpenFPGA architecture file.
For code readability, a routing multiplexer circuit model name should follow the convention
::
<Location>_mux_<Load>
.. option:: Location
Represents the location of the routing multiplexers, it can be
- ``cb`` denotes a routing multiplexer in a connection block
- ``sb`` denotes a routing multiplexer in a switch block
- ``pb`` denotes a routing multiplexer in a programmable block
.. option:: Load
Represents the output load condition of the routing multiplexers, it can be
- ``highload`` means that the routing multiplexer has to drive a very high capacitive load, which potentially requires a big buffer at output
- an empty string "" means the routing multiplexer requires only a typical buffer size.
A quick example
::
pb_mux_highload
represents a routing multiplexer used in a programmable block which drives a high capacitive load

View File

@ -1,16 +1,22 @@
.. _developer:
Developer Guidelines
.. toctree::
:maxdepth: 1
:maxdepth: 2
version_number
back_compatible
contributor_guidelines
cicd_setup
ci
regression_tests
tcl_api
.. toctree::
:maxdepth: 2
:caption: Contributor Guidelines
contributor_guidelines/index

View File

@ -88,6 +88,23 @@ Layout
.. warning:: Do NOT enable ``shrink_boundary`` if you are not using the tileable routing resource graph generator!
.. option:: perimeter_cb="<bool>"
Allow connection blocks to appear around the perimeter programmable block (mainly I/Os). This is designed to enhance routability of I/Os on perimeter. Also strongly recommended when programmable clock network is required to touch clock pins on I/Os. As illustrated in :numref:`fig_perimeter_cb`, routing tracks can access three sides of each I/O when perimeter connection blocks are created.
By default, it is ``false``.
.. warning:: When enabled, please only place outputs at one side of I/Os. For example, outputs of an I/O on the top side can only occur on the bottom side of the I/O tile. Otherwise, routability loss may be expected, leading to some pins cannot be reachable. Enable the ``opin2all_sides`` to recover routability loss.
.. _fig_perimeter_cb:
.. figure:: ./figures/perimeter_cb.png
:width: 100%
:alt: Impact of perimeter_cb
Impact on routing architecture when perimeter connection blocks are : (a) disabled; (b) enabled.
.. warning:: Do NOT enable ``perimeter_cb`` if you are not using the tileable routing resource graph generator!
.. option:: opin2all_sides="<bool>"
Allow each output pin of a programmable block to drive the routing tracks on all the sides of its adjacent switch block (see an illustrative example in :numref:`fig_opin2all_sides`). This can improve the routability of an FPGA fabric with an increase in the sizes of routing multiplexers in each switch block.

View File

@ -79,6 +79,7 @@ For subtile port merge support (see an illustrative example in :numref:`fig_subt
.. note:: When defined, the given port of all the subtiles of a tile will be merged into one port. For example, a tile consists of 8 subtile ``A`` and 6 subtile ``B`` and all the subtiles have a port ``clk``, in the FPGA fabric, all the ``clk`` of the subtiles ``A`` and ``B`` will be wired to a common port ``clk`` at tile level.
.. note:: Note that when a dedicated clock network is defined, the size of the global port will follow the ``global_port`` defined in the clock network description file (See details in :ref:`file_formats_clock_network`)
.. note:: When merged, the port will have a default side of ``TOP`` and index of ``0`` on all the attributes, such as width, height etc.
@ -99,6 +100,8 @@ For global port support:
- ``clock_arch_tree_name="<string>"`` defines the name of the programmable clock network, which the global port will drive. The name of the programmable clock network must be a valid name (See details in :ref:`file_formats_clock_network`)
.. note:: ``clock_arch_tree_name`` is applicable to clock, reset and set signals.
- ``is_reset="<bool>"`` define if the global port is a reset port at the top-level FPGA fabric. An operating reset port will be driven by proper signals in testbenches.
- ``is_set="<bool>"`` define if the global port is a set port at the top-level FPGA fabric. An operating set port will be driven by proper signals in testbenches.

View File

@ -53,6 +53,7 @@ Here, we focus these common syntax and we will detail special syntax in :ref:`ci
<input_buffer exist="<string>" circuit_model_name="<string>"/>
<output_buffer exist="<string>" circuit_model_name="<string>"/>
<pass_gate_logic type="<string>" circuit_model_name="<string>"/>
<last_stage_pass_gate_logic type="<string>" circuit_model_name="<string>"/>
<port type="<string>" prefix="<string>" lib_name="<string>" size="<int>" default_val="<int>" circuit_model_name="<string>" mode_select="<bool>" is_global="<bool>" is_set="<bool>" is_reset="<bool>" is_config_enable="<bool>"/>
<!-- more ports -->
</circuit_model>
@ -129,12 +130,16 @@ Input and Output Buffers
Pass Gate Logic
^^^^^^^^^^^^^^^
.. note:: pass-gate logic are used in building multiplexers and LUTs.
.. option:: <pass_gate_logic circuit_model_name="<string>"/>
- ``circuit_model_name="<string>"`` Specify the name of the circuit model which is used to implement pass-gate logic, the type of specified circuit model should be ``pass_gate``.
.. note:: pass-gate logic are used in building multiplexers and LUTs.
.. option:: <last_stage_pass_gate_logic circuit_model_name="<string>"/>
- ``circuit_model_name="<string>"`` Specify the name of the circuit model which is used to implement the pass-gate logic at last stage of multiplexer, the type of specified circuit model should be ``pass_gate``. The type of the pass-gate logic circuit model must be a standard cell MUX2!
.. _circuit_library_circuit_port:

View File

@ -619,6 +619,14 @@ This example shows:
Standard Cell Multiplexer
`````````````````````````
.. _fig_stdcellmux:
.. figure:: ./figures/stdcellmux.png
:width: 100%
:alt: Examples of MUX built with standard cells
An example of a multiplexer built with standard cells: (a) all the MUX2 are the same; (b) the MUX2 at the last stage is a different one
.. code-block:: xml
<circuit_model type="mux" name="mux_stdcell" prefix="mux_stdcell">
@ -631,12 +639,34 @@ Standard Cell Multiplexer
<port type="sram" prefix="sram" size="3"/>
</circuit_model>
This example shows:
This example shows (see an illustative example in :numref:`fig_stdcellmux` (a)):
- A tree-like 4-input CMOS multiplexer built by the standard cell ``MUX2``
- All the inputs will be buffered using the circuit model ``inv1x``
- All the outputs will be buffered using the circuit model ``tapbuf4``
- The multiplexer will have 4 inputs and 3 SRAMs to control which datapath to propagate
Alternatively, user can specify a different standard cell MUX2 at the last stage.
.. code-block:: xml
<circuit_model type="mux" name="mux_stdcell" prefix="mux_stdcell">
<design_technology type="cmos" structure="tree"/>
<input_buffer exist="on" circuit_model_name="inv1x"/>
<output_buffer exist="on" circuit_model_name="tapdrive4"/>
<pass_gate_logic circuit_model_name="MUX2"/>
<last_stage_pass_gate_logic circuit_model_name="MUX2D2"/>
<port type="input" prefix="in" size="4"/>
<port type="output" prefix="out" size="1"/>
<port type="sram" prefix="sram" size="3"/>
</circuit_model>
This example shows (see an illustative example in :numref:`fig_stdcellmux` (b)):
- A tree-like 4-input CMOS multiplexer built by the standard cell ``MUX2``
- The last stage A tree-like 4-input CMOS multiplexer built by the standard cell ``MUX2``
- All the inputs will be buffered using the circuit model ``inv1x``
- All the outputs will be buffered using the circuit model ``tapbuf4``
- The multiplexer will have 4 inputs and 3 SRAMs to control which datapath to propagate
.. _circuit_model_mux_multilevel_example:
Multi-level Multiplexer

View File

@ -7,6 +7,17 @@ Configuration protocol is the circuitry designed to program an FPGA.
As an interface, configuration protocol could be really different in FPGAs, depending on the application context.
OpenFPGA supports versatile configuration protocol, providing different trade-offs between speed and area.
Under configuration protocol, if the configuration is QL Memory Bank with flatten BL/WL protocol, there might be
optional configuration setting call <ql_memory_bank_config_setting>.
In QL Memory Bank configuration protocol, configuration bits are organized as BitLine (BL) x WordLine (WL)
By default, OpenFPGA will keep BL and WL in square shape if possible where BL might be one bit longer than WL in some cases
For example:
- If the configuration bits of a PB is 9 bits, then BL=3 and WL=3
- If the configuration bits of a PB is 11 bits, then BL=4 and WL=3 (where there is one extra bit as phantom bit)
- If the configuration bits of a PB is 14 bits, then BL=4 and WL=4 (where there is two extra bits as phantom bits)
This QL Memory Bank configuration setting allow OpenFPGA to use a fixed WL size, instead of default approach
Template
~~~~~~~~
@ -14,6 +25,9 @@ Template
<configuration_protocol>
<organization type="<string>" circuit_model_name="<string>" num_regions="<int>"/>
<ql_memory_bank_config_setting>
<pb_type name="<string>" num_wl="<int>"/>
</ql_memory_bank_config_setting>
</configuration_protocol>
.. option:: type="scan_chain|memory_bank|standalone|frame_based|ql_memory_bank"
@ -54,6 +68,29 @@ Template
.. note:: For ``ql_memory_bank`` configuration protocol when BL/WL protocol ``shift_register`` is selected, different configuration regions **cannot** share any WLs on the same row! In such case, the default fabric key may not work. Strongly recommend to craft your own fabric key based on your configuration region plannning!
.. option:: name="<string>"
Specify the name of PB type, for example: clb, dsp, bram and etc
.. option:: num_wl="<int>"
Fix the size of WL
For example:
Considered that the configuration bits of a PB is 400 bits.
If num_wl is not defined, then
- BL will be 20 [=ceiling(square_root(400))]
- WL will be 20 [=ceiling(400/20)]
If num_wl is defined as 10, then
- WL will be fixed as 10
- BL will be 40 [=ceiling(400/10)]
If num_wl is defined as 32, then
- WL will be fixed as 32
- BL will be 13 [=ceiling(400/32)]
- There will be 16 bits [=(32x13)-400] as phantom bits.
Configuration Chain Example
~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -1,12 +1,12 @@
.. _direct_interconnect:
Inter-Tile Direct Interconnection extensions
--------------------------------------------
Direct Interconnect
-------------------
This section introduces extensions on the architecture description file about existing interconnection description.
This section introduces extensions on the architecture description file about direct connections between programmable blocks.
Directlist
~~~~~~~~~~
Syntax
~~~~~~
The original direct connections in the directlist section are documented here_. Its description is given below:
@ -20,20 +20,26 @@ The original direct connections in the directlist section are documented here_.
.. note:: These options are required
Our extension include three more options:
In the OpenFPGA architecture file, you may define additional attributes for each VPR's direct connection:
.. code-block:: xml
<directlist>
<direct name="string" from_pin="string" to_pin="string" x_offset="int" y_offset="int" z_offset="int" switch_name="string" interconnection_type="string" x_dir="string" y_dir="string"/>
<direct_connection>
<direct name="string" circuit_model_name="string" interconnection_type="string" x_dir="string" y_dir="string"/>
</directlist>
.. note:: these options are optional. However, if `interconnection_type` is set `x_dir` and `y_dir` are required.
.. note:: these options are optional. However, if ``interconnection_type`` is set to ``inter_column`` or ``inter_row``, then ``x_dir`` and ``y_dir`` are required.
.. option:: interconnection_type="<string>"
the type of interconnection should be a string.
Available types are ``NONE`` | ``column`` | ``row``, specifies if it applies on a column or a row ot if it doesn't apply.
Available types are ``inner_column_or_row`` | ``part_of_cb`` | ``inter_column`` | ``inter_row``
- ``inner_column_or_row`` indicates the direct connections are between tiles in the same column or row. This is the default value.
- ``part_of_cb`` indicates the direct connections will drive routing multiplexers in connection blocks. Therefore, it is no longer a strict point-to-point direct connection.
- ``inter_column`` indicates the direct connections are between tiles in two columns
- ``inter_row`` indicates the direct connections are between tiles in two rows
.. note:: The following syntax is only applicable to ``inter_column`` and ``inter_row``
.. option:: x_dir="<string>"
@ -42,15 +48,15 @@ Our extension include three more options:
- x_dir="positive":
- interconnection_type="column": a column will be connected to a column on the ``right``, if it exists.
- interconnection_type="inter_column": a column will be connected to a column on the ``right``, if it exists.
- interconnection_type="row": the most on the ``right`` cell from a row connection will connect the most on the ``left`` cell of next row, if it exists.
- interconnection_type="inter_row": the most on the ``right`` cell from a row connection will connect the most on the ``left`` cell of next row, if it exists.
- x_dir="negative":
- interconnection_type="column": a column will be connected to a column on the ``left``, if it exists.
- interconnection_type="inter_column": a column will be connected to a column on the ``left``, if it exists.
- interconnection_type="row": the most on the ``left`` cell from a row connection will connect the most on the ``right`` cell of next row, if it exists.
- interconnection_type="inter_row": the most on the ``left`` cell from a row connection will connect the most on the ``right`` cell of next row, if it exists.
.. option:: y_dir="<string>"
@ -59,27 +65,96 @@ Our extension include three more options:
- y_dir="positive":
- interconnection_type="column": the ``bottom`` cell of a column will be connected to the next column ``top`` cell, if it exists.
- interconnection_type="inter_column": the ``bottom`` cell of a column will be connected to the next column ``top`` cell, if it exists.
- interconnection_type="row": a row will be connected on an ``above`` row, if it exists.
- interconnection_type="inter_row": a row will be connected on an ``above`` row, if it exists.
- y_dir="negative":
- interconnection_type="column": the ``top`` cell of a column will be connected to the next column ``bottom`` cell, if it exists.
- interconnection_type="inter_column": the ``top`` cell of a column will be connected to the next column ``bottom`` cell, if it exists.
- interconnection_type="row": a row will be connected on a row ``below``, if it exists.
- interconnection_type="inter_row": a row will be connected on a row ``below``, if it exists.
Example
~~~~~~~
Enhanced Connection Block
~~~~~~~~~~~~~~~~~~~~~~~~~
For this example, we will study a scan-chain implementation. The description could be:
The direct connection can also drive routing multiplexers of connection blocks. When such connection occures in a connection block, it is called enhanced connection block.
:numref:`fig_ecb` illustrates the difference between a regular connection block and an enhanced connection block.
.. _fig_ecb:
.. figure:: ./figures/ecb.png
Enhanced connection block vs. Regular connection block
In such scenario, the type ``part_of_cb`` is required.
.. warning:: Restrictions may be applied when building the direct connections as part of a connection block.
Direct connections can be inside a tile or across two tiles. Currently, across more than two tiles are not supported!
:numref:`fig_ecb_allowed_direct_connection` illustrates the region (in red) where any input pin is allowed to be driven by any output pin.
.. _fig_ecb_allowed_direct_connection:
.. figure:: ./figures/ecb_allowed_direct_connection.png
Allowed connections inside a tile for enhanced connection block (see the highlighted region)
:numref:`fig_ecb_allowed_direct_connection_inner_tile_example` shows a few feedback connections which can be built inside connection blocks. Note that feedback connections are fully allowed between any pins on the same side of a programmable block.
.. _fig_ecb_allowed_direct_connection_inner_tile_example:
.. figure:: ./figures/ecb_allowed_direct_connection_inner_tile_example.png
Example of feedback connections inside a tile for enhanced connection block
For instance, VPR architecture defines feedback connections like:
.. code-block:: xml
<directlist>
<direct name="scff_chain" from_pin="clb.sc_out" to_pin="clb.sc_in" x_offset="0" y_offset="-1" z_offset="0" interconnection_type="column" x_dir="positive" y_dir="positive"/>
<!-- Add 2 inputs to the routing multiplexers inside a connection block which drives pin 'clb.I_top[0]' -->
<direct name="feedback" from_pin="clb.O_top[0:0]" to_pin="clb.I_top[0:0]" x_offset="0" y_offset="0" z_offset="0"/>
<direct name="feedback" from_pin="clb.O_top[1:1]" to_pin="clb.I_top[0:0]" x_offset="0" y_offset="0" z_offset="0"/>
</directlist>
:numref:`fig_ecb_allowed_direct_connection_inter_tile_example` shows a few inter-tile connections which can be built inside connection blocks. Note that inter-tile connections are subjected to the restrictions depicted in :numref:`fig_ecb_allowed_direct_connection`
.. _fig_ecb_allowed_direct_connection_inter_tile_example:
.. figure:: ./figures/ecb_allowed_direct_connection_inter_tile_example.png
Example of connections across two tiles for enhanced connection block
:numref:`fig_ecb_forbid_direct_connection_example` illustrates some inner-tile and inter-tile connections which are not allowed. Note that feedback connections across different sides are restricted!
.. _fig_ecb_forbid_direct_connection_example:
.. figure:: ./figures/ecb_forbid_direct_connection_example.png
Restrictions on building direct connections as part of a connection block
Inter-tile Connections
~~~~~~~~~~~~~~~~~~~~~~
For this example, we will study a scan-chain implementation. The description could be:
In VPR architecture:
.. code-block:: xml
<directlist>
<direct name="scff_chain" from_pin="clb.sc_out" to_pin="clb.sc_in" x_offset="0" y_offset="-1" z_offset="0"/>
</directlist>
In OpenFPGA architecture:
.. code-block:: xml
<direct_connection>
<direct name="scff_chain" interconnection_type="column" x_dir="positive" y_dir="positive"/>
</direct_connection>
:numref:`fig_p2p_exple` is the graphical representation of the above scan-chain description on a 4x4 FPGA.
.. _fig_p2p_exple:
@ -91,9 +166,6 @@ For this example, we will study a scan-chain implementation. The description cou
In this figure, the red arrows represent the initial direct connection. The green arrows represent the point to point connection to connect all the columns of CLB.
Truth table
~~~~~~~~~~~
A point to point connection can be applied in different ways than showed in the example section. To help the designer implement his point to point connection, a truth table with our new parameters id provided below.
:numref:`fig_p2p_trtable` provides all possible variable combination and the connection it will generate.

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -13,6 +13,12 @@ This can define a hard-coded bitstream for a reconfigurable resource in FPGA fab
<openfpga_bitstream_setting>
<pb_type name="<string>" source="eblif" content=".param LUT" is_mode_select_bistream="true" bitstream_offset="1"/>
<interconnect name="<string>" default_path="<string>"/>
<non_fabric name="<string>" file="<string>">
<pb name="<string>" type="<string>" content="<string>"/>
</non_fabric>
<overwrite_bitstream>
<bit value="<0 or 1>" path="<string>"/>
</overwrite_bitstream>
</openfpga_bitstream_setting>
pb_type-related Settings
@ -40,7 +46,6 @@ The following syntax are applicable to the XML definition tagged by ``pb_type``
The content of the ``pb_type`` bitstream, which could be a keyword in a ``.eblif`` file. For example, ``content=".attr LUT"`` means that the bitstream will be extracted from the ``.attr LUT`` line which is defined under the ``.blif model`` (that is defined under the ``pb_type`` in VPR architecture file).
.. option:: is_mode_select_bitstream="<bool>"
Can be either ``true`` or ``false``. When set ``true``, the bitstream is considered as mode-selection bitstream, which may overwrite ``mode_bits`` definition in ``pb_type_annotation`` of OpenFPGA architecture description. (See details in :ref:`annotate_vpr_arch_pb_type_annotation`)
@ -71,3 +76,72 @@ The following syntax are applicable to the XML definition tagged by ``interconne
<mux name="mux1" input="iopad.inpad ff.Q" output="io.inpad"/>
The default path can be either ``iopad.inpad`` or ``ff.Q`` which corresponds to the first input and the second input respectively.
non_fabric-related Settings
^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is special syntax to extract PB defined parameter or attribute and save the data into dedicated JSON file outside of fabric bitstream
The following syntax are applicable to the XML definition tagged by ``non_fabric`` in bitstream setting files.
.. option:: name="<string: pb_type top level name>"
The ``pb_type`` top level name that the data to be extracted. For example,
.. code-block:: xml
name="bram"
.. option:: file="<string: JSON filepath>"
The filepath the data is saved to. For example,
.. code-block:: xml
file="bram.json"
.. option:: pb child element name="<string: pb_type child name>"
Together with ``pb_type`` top level name, that is the source of the ``pb_type`` bitstream
The final ``pb_type`` name is "<pb_type top level name>" + "<pb_type child name>"
For example,
.. code-block:: xml
<non_fabric name="bram" file="bram_bitstream.json">
<pb name=".bram_lr[mem_36K_tdp].mem_36K" content=".param INIT_i"/>
</non_fabric>
The final ``pb_type`` name is "bram.bram_lr[mem_36K_tdp].mem_36K"
.. option:: pb child element content="<string>"
The content of the ``pb_type`` data to be extracted. For example, ``content=".param INIT_i"`` means that the data will be extracted from the ``.param INIT_i`` line defined under the ``.blif model``.
overwrite_bitstream-related Settings
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is to allow user to set value of a list of bits which is represented using full path in the hierarchy of FPGA fabric
This ``overwrite_bitstream`` settings has the highest priority than loading any external bitstream file
Each bit to overwrite is represented by one ``bit`` child node/tag
The following syntax are applicable to the XML definition tagged by ``bit`` node under ``overwrite_bitstream`` setting.
.. option:: value="<0 or 1>"
The boolean ``0`` or ``1`` that will be set. For example,
.. code-block:: xml
value="0"
.. option:: path="<string>"
``path`` represents the location of this block in FPGA fabric, i.e., the full path in the hierarchy of FPGA fabric.
.. code-block:: xml
path="fpga_top.grid_clb_1__2_.logical_tile_clb_mode_clb__0.mem_fle_9_in_5[0]"

View File

@ -14,6 +14,8 @@ Using the clock network description language, users can define multiple clock ne
- A number of switch points which interconnects clock spines using programmable routing switches. See details in :ref:`file_formats_clock_network_switch_point`.
- A number of tap points which connect the clock spines to programmable blocks, e.g., CLBs. See details in :ref:`file_formats_clock_network_tap_point`.
The entry point of a clock tree must be at a valid connection block.
.. note:: Please note that the levels of a clock network will be automatically inferred from the clock spines and switch points. Clock network will be **only** built based on the width and the number of levels, as well as the tap points.
.. note:: The switch points and clock spines will be used to route a clock network. The switch points will not impact the physical clock network but only impact the configuration of the programmable routing switches in the physical clock network.
@ -22,17 +24,43 @@ Using the clock network description language, users can define multiple clock ne
.. code-block:: xml
<clock_networks default_segment="<string>" default_switch="<string>">
<clock_network name="<string>" width="<int>">
<clock_networks default_segment="<string>" default_tap_switch="<string>" default_driver_switch="<string>">
<clock_network name="<string>" global_port="<int>">
<spine name="<string>" start_x="<int>" start_y="<int>" end_x="<int>" end_y="<int>">
<switch_point tap="<string>" x="<int>" y="<int>"/>
<intermediate_driver x="<int>" y="<int>">
<tap from_pin="<string>" to_pin="<string>"/>
</intermediate_driver>
<switch_point tap="<string>" x="<int>" y="<int>">
<internal_driver from_pin="<string>" to_pin="<string>"/>
</switch_point>
</spine>
<taps>
<tap tile_pin="<string>"/>
<all from_pin="<string>" to_pin="<string>"/>
<region from_pin="<string>" to_pin="<string>" start_x="<int>" start_y="<int>" end_x="<int>" end_y="<int>" repeat_x="<int>" repeat_y="<int>"/>
<single from_pin="<string>" to_pin="<string>" x="<int>" y="<int>"/>
</taps>
</clock_network>
</clock_networks>
.. _fig_prog_clock_network_example_2x2:
.. figure:: figures/prog_clk_network_example_2x2.png
:width: 100%
:alt: An example of programmable clock network considering a 2x2 FPGA fabric
An example of programmable clock network considering a 2x2 FPGA fabric
Note that when the ``perimeter_cb`` is enabled for routing architecture (See details in :ref:`addon_vpr_syntax`), clock entry point can be indeed at the fringe of FPGA fabrics. See example in :numref:`prog_clock_network_example_2x2_perimeter_cb`.
.. _fig_prog_clock_network_example_2x2_perimeter_cb:
.. figure:: figures/prog_clk_network_example_2x2_perimeter_cb.png
:width: 100%
:alt: An example of programmable clock network considering a 2x2 FPGA fabric with perimeter cb
An example of programmable clock network considering a 2x2 FPGA fabric with perimeter cb
General Settings
^^^^^^^^^^^^^^^^
@ -40,7 +68,7 @@ The following syntax are applicable to the XML definition under the root node ``
.. option:: default_segment="<string>"
Define the default routing segment to be used when building the routing tracks for the clock network. Must be a valid routing segment defined in the VPR architecture file. For example,
Define the default routing segment to be used when building the routing tracks for the clock network. The routing segments are used to build the spines of clock networks as shown in :numref:`fig_prog_clock_network_example_2x2`. Must be a valid routing segment defined in the VPR architecture file. For example,
.. code-block:: xml
@ -56,23 +84,30 @@ where the segment is defined in the VPR architecture file:
.. note:: Currently, clock network requires only length-1 wire segment to be used!
.. option:: default_switch="<string>"
.. option:: default_tap_switch="<string>"
Define the default routing switch to be used when interconnects the routing tracks in the clock network. Must be a valid routing switch defined in the VPR architecture file. For example,
Define the default routing switch to be used when interconnects the routing tracks to the input pins of programmable blocks in the clock network. The tap switches are used to build the taps of clock networks as shown in :numref:`fig_prog_clock_network_example_2x2`. Must be a valid routing switch defined in the VPR architecture file. See the example in the ``default_driver_switch``.
.. option:: default_driver_switch="<string>"
.. note:: For internal drivers, suggest to use the same driver switch for the output pins of a programmable block as defined in VPR architecture.
Define the default routing switch to be used when interconnects the routing tracks in the clock network. The driver switches are used to build the switch points of clock networks as shown in :numref:`fig_prog_clock_network_example_2x2`. Must be a valid routing switch defined in the VPR architecture file. For example,
.. code-block:: xml
default_switch="clk_mux"
default_tap_switch="cb_mux" default_driver_switch="sb_clk_mux"
where the switch is defined in the VPR architecture file:
.. code-block:: xml
<switchlist>
<switch type="mux" name="clk_mux" R="551" Cin=".77e-15" Cout="4e-15" Tdel="58e-12" mux_trans_size="2.630740" buf_size="27.645901"/>
<switch type="mux" name="cb_mux" R="551" Cin=".77e-15" Cout="4e-15" Tdel="58e-12" mux_trans_size="2.630740" buf_size="27.645901"/>
<switch type="mux" name="sb_clk_mux" R="55" Cin=".7e-15" Cout="4e-15" Tdel="58e-12" mux_trans_size="2.630740" buf_size="27.645901"/>
</switchlist>
.. note:: Currently, clock network only supports one type of routing switch, which means all the programmable routing switch in the clock network will be in the same type and circuit design topology.
.. note:: Currently, clock network only supports the default types of routing switch, which means all the programmable routing switch in the clock network will be in the same type and circuit design topology.
Clock Network Settings
^^^^^^^^^^^^^^^^^^^^^^
@ -94,13 +129,18 @@ where the clock network is used to drive the global clock pin ``clk0`` in OpenFP
<tile_annotations>
<global_port name="clk0" is_clock="true" clock_arch_tree_name="clk_tree_0" default_val="0">
<tile name="clb" port="clk[0:1]"
<tile name="clb" port="clk[0:0]"/>
</global_port>
</tile_annotations>
.. option:: width="<int>"
.. option:: global_port="<string>"
The maximum number of clock pins that a clock network can drive.
.. note:: When programmable clock network is specified for a global port in OpenFPGA architecure description file, the width of clock tree will be the final size of the global port.
Define the source port of the clock network. For example, ``clk[0:7]``. Note that the global port name should match
- the ``from_pin`` when defining the tap points (See details in :ref:`file_formats_clock_network_clock_tap_point`).
- the ``name`` of global port definition in OpenFPGA architecture description file
.. _file_formats_clock_network_clock_spine:
@ -110,6 +150,8 @@ Clock Spine Settings
The following syntax are applicable to the XML definition tagged by ``spine``.
Note that a number of clock spines can be defined under the node ``clock_network``.
.. note:: Use coordinates of connection blocks to define the starting and ending points of clock spines.
.. option:: name="<string>"
The unique name of the clock spine. It will be used to build switch points between other clock spines.
@ -136,10 +178,66 @@ For example,
<spine name="spine0" start_x="1" start_y="1" end_x="2" end_y="1"/>
where a horizental clock spine ``spine0`` is defined which spans from (1, 1) to (2, 1)
where a horizental clock spine ``spine0`` is defined which spans from (1, 1) to (2, 1), as highlighted in orange in the :numref:`fig_prog_clock_network_example_2x2`
.. note:: We only support clock spines in horizental and vertical directions. Diagonal clock spine is not supported!
.. _file_formats_clock_network_intermediate_driver:
Intermediate Driver
^^^^^^^^^^^^^^^^^^^
The following syntax are applicable to the XML definition tagged by ``intermediate_driver``
Note that a number of intermediate drivers can be defined under each clock spine ``spine``.
.. option:: x="<int>"
The coordinate X where the intermediate driver should occur on the spine. Must be a valid coordinate within the range of the current clock spine and the clock spine to be tapped.
.. option:: y="<int>"
The coordinate Y where the intermediate driver should occur on the spine. Must be a valid coordinate within the range of the current clock spine and the clock spine to be tapped.
.. note:: The intermeidate driver is different than the internal driver (see details in :ref:`file_formats_clock_network_switch_point`). Intermediate driver may occur in any mid points of a spine, while internal driver occurs **ONLY** on the switch points between spines.
Under each intermediate driver, a number of tap points can be specified.
For each tap point, outputs of neighbouring programmable blocks are allowed to drive the spine through syntax ``tap``.
.. option:: from_pin="<string>"
Define the pin of a programmable block as an internal driver to a clock network. The pin must be a valid pin defined in the VPR architecture description file.
.. option:: to_pin="<string>"
Define the source pin of a clock network. The pin must be a valid pin of the global ports defined in the tile_annotation part of OpenFPGA architecture description file.
For example,
.. code-block:: xml
<clock_network name="clk_tree_0" global_port="clk[0:1]">
<!-- Some clock spines -->
<spine name="spine0" start_x="1" start_y="1" end_x="2" end_y="1">
<intermediate_driver x="1" y="1">
<tap from_pin="clb.O[0:1]" to_pin="clk[0:0]"/>
</intermediate_driver>
<spine>
</clock_network>
where clock spine ``spine0`` will be driven by other programmable blocks at (1, 1), as highlighted in purple in the :numref:`fig_prog_clock_network_example_2x2_perimeter_cb`
To be specific, the clock routing can be driven at (x=1,y=1) by the output pins ``O[0:3]`` of tile ``clb`` in a VPR architecture description file:
.. code-block:: xml
<tile name="clb">
<sub_tile name="clb">
<output name="O" num_pins="8"/>
</sub_tile>
</tile>
.. _file_formats_clock_network_switch_point:
Switch Point Settings
@ -148,6 +246,8 @@ Switch Point Settings
The following syntax are applicable to the XML definition tagged by ``switch_point``.
Note that a number of switch points can be defined under each clock spine ``spine``.
.. note:: Use the coordinate of switch block to define switching points!
.. option:: tap="<string>"
Define which clock spine will be tapped from the current clock spine.
@ -168,40 +268,126 @@ For example,
<switch_point tap="spine1" x="1" y="1"/>
<spine>
where clock spine ``spine0`` will drive another clock spine ``spine1`` at (1, 1).
where clock spine ``spine0`` will drive another clock spine ``spine1`` at (1, 1), as highlighted in blue in the :numref:`fig_prog_clock_network_example_2x2`
For each switch point, outputs of neighbouring programmable blocks are allowed to drive the spine at next level, through syntax ``internal_driver``.
.. option:: from_pin="<string>"
Define the pin of a programmable block as an internal driver to a clock network. The pin must be a valid pin defined in the VPR architecture description file.
.. option:: to_pin="<string>"
Define the source pin of a clock network. The pin must be a valid pin of the global ports defined in the tile_annotation part of OpenFPGA architecture description file.
For example,
.. code-block:: xml
<clock_network name="clk_tree_0" global_port="clk[0:1]">
<!-- Some clock spines -->
<spine name="spine0" start_x="1" start_y="1" end_x="2" end_y="1">
<switch_point tap="spine1" x="1" y="1">
<internal_driver from_pin="clb.O[0:1]" to_pin="clk[0:0]"/>
</switch_point>
<spine>
</clock_network>
where the clock routing can be driven at (x=1,y=1) by the output pins ``O[0:3]`` of tile ``clb`` in a VPR architecture description file:
.. code-block:: xml
<tile name="clb">
<sub_tile name="clb">
<output name="O" num_pins="8"/>
</sub_tile>
</tile>
.. _file_formats_clock_network_tap_point:
Tap Point Settings
^^^^^^^^^^^^^^^^^^
The following syntax are applicable to the XML definition tagged by ``tap``.
The following syntax are applicable to the XML definition tagged by ``all``, ``region`` and ``single``.
Note that a number of tap points can be defined under the node ``taps``.
.. option:: tile_pin="<string>"
.. option:: from_pin="<string>"
Define the pin of a programmable block to be tapped by a clock network. The pin must be a valid pin defined in the VPR architecture description file.
Define the source pin of a programmable block to be tapped by a clock network. The pin must be a valid pin of the global ports defined in the tile_annotation part of OpenFPGA architecture description file.
.. option:: to_pin="<string>"
Define the destination pin of a programmable block to be tapped by a clock network. The pin must be a valid pin defined in the VPR architecture description file.
.. note:: Only the leaf clock spine (not switch points to drive other clock spine) can tap pins of programmable blocks.
.. note:: Each coordinate must be a valid integer within the device height and width that are defined in VPR architecture!!!
.. warning:: The following syntax are only applicable to ``single`` tap mode.
.. option:: x="<int>"
Define the x coordinate of the tap point, which is applied to the destination pin ``to_pin``
.. option:: y="<int>"
Define the y coordinate of the tap point, which is applied to the destination pin ``to_pin``
.. warning:: The following syntax are only applicable to ``region`` tap mode.
.. option:: start_x="<int>"
Define the starting x coordinate of the tap region, which is applied to the destination pin ``to_pin``
.. option:: start_y="<int>"
Define the starting y coordinate of the tap region, which is applied to the destination pin ``to_pin``
.. option:: end_x="<int>"
Define the ending x coordinate of the tap region, which is applied to the destination pin ``to_pin``
.. option:: end_y="<int>"
Define the ending y coordinate of the tap region, which is applied to the destination pin ``to_pin``
.. option:: repeat_x="<int>"
Define the repeating factor on x coordinate of the tap region, which is applied to the destination pin ``to_pin``
.. option:: repeat_y="<int>"
Define the repeating factor on y coordinate of the tap region, which is applied to the destination pin ``to_pin``
For example,
.. code-block:: xml
<clock_network name="clk_tree_0" width="1">
<clock_network name="clk_tree_0" global_port="clk[0:1]">
<!-- Some clock spines -->
<taps>
<tap tile_pin="clb.clk"/>
<all from_pin="clk[0:0]" to_pin="clb[0:0].clk[0:0]"/>
<region from_pin="clk[1:1]" to_pin="clb[1:1].clk[1:1]" start_x="1" start_y="1" end_x="4" end_y="4" repeat_x="2" repeat_y="2"/>
<single from_pin="clk[1:1]" to_pin="clb[2:2].clk[1:1]" x="2" y="2"/>
</taps>
</clock_network>
where all the clock spines of the clock network ``clk_tree_0`` tap the clock pins ``clk`` of tile ``clb`` in a VPR architecture description file:
.. note:: Use the name of ``tile`` in the ``to_pin`` when there are a number of subtiles in your tile! Use the absolute index for the subtile in the tile.
.. code-block:: xml
<tile name="clb">
<sub_tile name="clb">
<clock name="clk" num_pins="1"/>
<!-- subtile index ranges [0:0] -->
<sub_tile name="clbM" capacity="1">
<clock name="clk" num_pins="2"/>
</sub_tile>
<!-- subtile index ranges [1:2] -->
<sub_tile name="clbA" capacity="2">
<clock name="clk" num_pins="2"/>
</sub_tile>
</tile>

View File

@ -0,0 +1,62 @@
.. _file_format_fabric_hierarchy_file:
Fabric Hierarchy File (.yaml)
----------------------------------------
This file is generated by command :ref:`openfpga_setup_commands_write_fabric_hierarchy`
The fabric hierarchy file aims to show module trees of a number of given roots
This file is created for netlist manipulation and detailed floorplanning during physical design steps
By using the options of the command :ref:`openfpga_setup_commands_write_fabric_hierarchy`, user can selectively output the module tree on their needs.
An example of the file is shown as follows.
.. code-block:: yaml
fpga_top:
tile_0__2_:
sb_0__1_:
mux_tree_tapbuf_size2:
INVTX1
const1
tap_buf4
mux_tree_tapbuf_basis_input2_mem1:
- TGATE
mux_tree_tapbuf_size2_feedthrough_mem
sb_1__config_group_mem_size40:
mux_tree_tapbuf_size2_mem:
- DFF
tile_1__2_:
grid_io_top:
logical_tile_io_mode_io_:
logical_tile_io_mode_physical__iopad:
- GPIO
- GPIO_feedthrough_DFF_mem
direct_interc
In this example, the root module is ``fpga_top``.
The child modules under ``fpga_top`` are ``tile_0__2_`` and ``tile_1__2_``.
Note that the leaf nodes are shown as a list, e.g., ``GPIO`` and ``GPIO_feedthrough_DFF_mem``.
When multiple root modules are defined, the output could be
.. code-block:: yaml
sb_0__1_:
- mux_tree_tapbuf_size2
sb_1__0_:
- mux_tree_tapbuf_size2
sb_1__1_:
- mux_tree_tapbuf_size2
cbx_1__0_:
- mux_tree_tapbuf_size4
cbx_1__1_:
- mux_tree_tapbuf_size4
cby_0__1_:
- mux_tree_tapbuf_size2
- mux_tree_tapbuf_size4
cby_1__1_:
- mux_tree_tapbuf_size4

View File

@ -0,0 +1,109 @@
.. _file_format_fabric_pin_physical_location_file:
Fabric Pin Physical Location File (.xml)
----------------------------------------
This file is generated by command :ref:`openfpga_setup_commands_write_fabric_pin_physical_location`
The fabric pin physical location file aims to show
- Pin names of each module in an eFPGA fabric
- Preferred physical side of each pin on its module
This file is created for pin guidelines during physical design steps
An example of the file is shown as follows.
.. code-block:: xml
<pin_location>
<module name="sb_1__1_">
<loc pin="chany_bottom_in[0:0]" side="bottom"/>
<loc pin="chany_bottom_in[1:1]" side="bottom"/>
<loc pin="chany_bottom_in[2:2]" side="bottom"/>
<loc pin="chany_bottom_in[3:3]" side="bottom"/>
<loc pin="chany_bottom_in[4:4]" side="bottom"/>
<loc pin="chany_bottom_in[5:5]" side="bottom"/>
<loc pin="chany_bottom_in[6:6]" side="bottom"/>
<loc pin="chany_bottom_in[7:7]" side="bottom"/>
<loc pin="chany_bottom_in[8:8]" side="bottom"/>
<loc pin="chany_bottom_in[9:9]" side="bottom"/>
<loc pin="chany_bottom_in[10:10]" side="bottom"/>
<loc pin="chany_bottom_in[11:11]" side="bottom"/>
<loc pin="chany_bottom_in[12:12]" side="bottom"/>
<loc pin="chany_bottom_out[0:0]" side="bottom"/>
<loc pin="chany_bottom_out[1:1]" side="bottom"/>
<loc pin="chany_bottom_out[2:2]" side="bottom"/>
<loc pin="chany_bottom_out[3:3]" side="bottom"/>
<loc pin="chany_bottom_out[4:4]" side="bottom"/>
<loc pin="chany_bottom_out[5:5]" side="bottom"/>
<loc pin="chany_bottom_out[6:6]" side="bottom"/>
<loc pin="chany_bottom_out[7:7]" side="bottom"/>
<loc pin="chany_bottom_out[8:8]" side="bottom"/>
<loc pin="chany_bottom_out[9:9]" side="bottom"/>
<loc pin="chany_bottom_out[10:10]" side="bottom"/>
<loc pin="chany_bottom_out[11:11]" side="bottom"/>
<loc pin="chany_bottom_out[12:12]" side="bottom"/>
<loc pin="bottom_right_grid_left_width_0_height_0_subtile_0__pin_inpad_0_[0:0]" side="bottom"/>
<loc pin="bottom_right_grid_left_width_0_height_0_subtile_1__pin_inpad_0_[0:0]" side="bottom"/>
<loc pin="bottom_right_grid_left_width_0_height_0_subtile_2__pin_inpad_0_[0:0]" side="bottom"/>
<loc pin="bottom_right_grid_left_width_0_height_0_subtile_3__pin_inpad_0_[0:0]" side="bottom"/>
<loc pin="bottom_right_grid_left_width_0_height_0_subtile_4__pin_inpad_0_[0:0]" side="bottom"/>
<loc pin="bottom_right_grid_left_width_0_height_0_subtile_5__pin_inpad_0_[0:0]" side="bottom"/>
<loc pin="bottom_right_grid_left_width_0_height_0_subtile_6__pin_inpad_0_[0:0]" side="bottom"/>
<loc pin="bottom_right_grid_left_width_0_height_0_subtile_7__pin_inpad_0_[0:0]" side="bottom"/>
<loc pin="bottom_left_grid_right_width_0_height_0_subtile_0__pin_O_3_[0:0]" side="bottom"/>
<loc pin="chanx_left_in[0:0]" side="left"/>
<loc pin="chanx_left_in[1:1]" side="left"/>
<loc pin="chanx_left_in[2:2]" side="left"/>
<loc pin="chanx_left_in[3:3]" side="left"/>
<loc pin="chanx_left_in[4:4]" side="left"/>
<loc pin="chanx_left_in[5:5]" side="left"/>
<loc pin="chanx_left_in[6:6]" side="left"/>
<loc pin="chanx_left_in[7:7]" side="left"/>
<loc pin="chanx_left_in[8:8]" side="left"/>
<loc pin="chanx_left_in[9:9]" side="left"/>
<loc pin="chanx_left_in[10:10]" side="left"/>
<loc pin="chanx_left_in[11:11]" side="left"/>
<loc pin="chanx_left_in[12:12]" side="left"/>
<loc pin="chanx_left_out[0:0]" side="left"/>
<loc pin="chanx_left_out[1:1]" side="left"/>
<loc pin="chanx_left_out[2:2]" side="left"/>
<loc pin="chanx_left_out[3:3]" side="left"/>
<loc pin="chanx_left_out[4:4]" side="left"/>
<loc pin="chanx_left_out[5:5]" side="left"/>
<loc pin="chanx_left_out[6:6]" side="left"/>
<loc pin="chanx_left_out[7:7]" side="left"/>
<loc pin="chanx_left_out[8:8]" side="left"/>
<loc pin="chanx_left_out[9:9]" side="left"/>
<loc pin="chanx_left_out[10:10]" side="left"/>
<loc pin="chanx_left_out[11:11]" side="left"/>
<loc pin="chanx_left_out[12:12]" side="left"/>
<loc pin="left_top_grid_bottom_width_0_height_0_subtile_0__pin_inpad_0_[0:0]" side="left"/>
<loc pin="left_top_grid_bottom_width_0_height_0_subtile_1__pin_inpad_0_[0:0]" side="left"/>
<loc pin="left_top_grid_bottom_width_0_height_0_subtile_2__pin_inpad_0_[0:0]" side="left"/>
<loc pin="left_top_grid_bottom_width_0_height_0_subtile_3__pin_inpad_0_[0:0]" side="left"/>
<loc pin="left_top_grid_bottom_width_0_height_0_subtile_4__pin_inpad_0_[0:0]" side="left"/>
<loc pin="left_top_grid_bottom_width_0_height_0_subtile_5__pin_inpad_0_[0:0]" side="left"/>
<loc pin="left_top_grid_bottom_width_0_height_0_subtile_6__pin_inpad_0_[0:0]" side="left"/>
<loc pin="left_top_grid_bottom_width_0_height_0_subtile_7__pin_inpad_0_[0:0]" side="left"/>
<loc pin="left_bottom_grid_top_width_0_height_0_subtile_0__pin_O_2_[0:0]" side="left"/>
</module>
</pin_location>
.. option:: name="<string>"
The module name in FPGA fabric, which should be a valid module defined in output Verilog netlist.
.. note:: You should be find the exact module in the FPGA fabric if you output the Verilog netlists.
.. option:: pin="<string>"
The name of the pin in FPGA fabric. Note that all the bus port will be flatten in this file.
.. note:: You should be find the exact pin in the module if you output the Verilog netlists.
.. option:: side="<string>"
The physical side of the pin should appear on the perimeter of the module.

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

View File

@ -41,3 +41,11 @@ OpenFPGA widely uses XML format for interchangeable files
module_naming_file
tile_config_file
fabric_pin_physical_location_file
fabric_hierarchy_file
reference_file
unique_blocks

View File

@ -0,0 +1,80 @@
.. _file_format_reference_file:
Reference File (.yaml)
----------------------------------------
This file is generated by command :ref:`openfpga_setup_commands_report_reference`
The reference file aims to the show reference number of each child module of given parent module
By using the options of the command :ref:`openfpga_setup_commands_report_reference`, user can selectively output the reference info under the given parent module on their needs.
An example of the file is shown as follows.
.. code-block:: yaml
Date: Mon Sep 9 16:41:53 2024
#the instance names are given during netlist generation
references:
- module: grid_io_top
count: 1
instances:
- grid_io_top_1__2_
- module: grid_io_right
count: 1
instances:
- grid_io_right_2__1_
- module: grid_io_bottom
count: 1
instances:
- grid_io_bottom_1__0_
- module: grid_io_left
count: 1
instances:
- grid_io_left_0__1_
- module: grid_clb
count: 1
instances:
- grid_clb_1__1_
- module: sb_0__0_
count: 1
instances:
- sb_0__0_
- module: sb_0__1_
count: 1
instances:
- sb_0__1_
- module: sb_1__0_
count: 1
instances:
- sb_1__0_
- module: sb_1__1_
count: 1
instances:
- sb_1__1_
- module: cbx_1__0_
count: 1
instances:
- cbx_1__0_
- module: cbx_1__1_
count: 1
instances:
- cbx_1__1_
- module: cby_0__1_
count: 1
instances:
- cby_0__1_
- module: cby_1__1_
count: 1
instances:
- cby_1__1_
In this example, the parent module is ``fpga_top``.
The child modules under ``fpga_top`` are ``grid_io_top``, ``grid_io_right``, and etc.
The instance of the child module ``grid_io_top`` is shown as a list as below:
- grid_io_top_1__2_

View File

@ -24,10 +24,12 @@ Detailed syntax are presented as follows.
Specify the style of tile organization. Can be [``top_left`` | ``top_right`` | ``bottom_left`` | ``bottom_right`` | ``custom``]
.. warning:: Currently, only ``top_left`` is supported!
.. warning:: Currently, only ``top_left`` and ``bottom_left`` are supported!
The ``top_left`` is a shortcut to define the organization for all the tiles. :numref:`fig_tile_style_top_left` shows an example of tiles in the top-left sytle, where the programmable block locates in the top-left corner of all the tiles, surrounded by two connection blocks and one switch blocks.
The ``bottom_left`` is a shortcut to define the organization for all the tiles. :numref:`fig_tile_style_bottom_left` shows an example of tiles in the bottom-left sytle, where the programmable block locates in the bottom-left corner of all the tiles, surrounded by two connection blocks and one switch blocks.
.. _fig_tile_style_top_left:
.. figure:: ./figures/tile_style_top_left.png
@ -37,3 +39,12 @@ Detailed syntax are presented as follows.
An example of top-left style of a tile in FPGA fabric
.. _fig_tile_style_bottom_left:
.. figure:: ./figures/tile_style_bottom_left.png
:width: 100%
:alt: An example of bottom-left style of tile
An example of bottom-left style of a tile in FPGA fabric

View File

@ -0,0 +1,50 @@
.. _file_formats_unique_blocks:
Unique Blocks (.xml)
--------------------
A unique blocks file is formatted in XML. The unique blocks can be of type ``cbx``, ``cby``, or ``sb``. As illustrated by the XML code below, the file includes the type and coordinates of these unique blocks, as well as the coordinates of their corresponding instances.
Configurable Block
~~~~~~~~~~~~~~~~~~
Unique blocks can be applied to various blocks, each of which can be of type ``cbx``, ``cby``, or ``sb``, and may have different coordinates.
.. note::
For each block, a set of keys can be defined. For unique blocks, both keys and instances can be specified. However, if a unique block does not have an instance, only keys are permitted.
- ``type`` specifies the type of the unique block in the FPGA fabric. Valid values for ``type`` are ``cbx``, ``cby``, or ``sb``.
- ``x`` represents the x-coordinate of the unique block.
- ``y`` represents the y-coordinate of the unique block.
Configurable Instance
~~~~~~~~~~~~~~~~~~~~~
A specific unique block can have multiple instances, where each instance is a mirrored version of the unique block. Each instance shares the same type as its parent block and includes information about its coordinates.
.. note::
- ``x`` specifies the x-coordinate of the instance.
- ``y`` specifies the y-coordinate of the instance.
The following content provides an example of a unique block file:
.. code-block:: xml
<unique_blocks>
<block type="sb" x="0" y="0"/>
<block type="sb" x="0" y="1"/>
<block type="sb" x="1" y="0"/>
<block type="sb" x="1" y="1"/>
<block type="cbx" x="1" y="0">
<instance x="0" y="0"/>
<instance x="0" y="1"/>
</block>
<block type="cbx" x="1" y="1"/>
<block type="cby" x="0" y="1">
<instance x="0" y="0"/>
<instance x="1" y="0"/>
</block>
<block type="cby" x="1" y="1"/>
</unique_blocks>

View File

@ -29,9 +29,9 @@ Similarly ``regression/regression_quick`` expect following structure::
Running OpenFPGA Task:
~~~~~~~~~~~~~~~~~~~~~~
At a minimum ``open_fpga_flow.py`` requires following command-line arguments::
At a minimum ``run_fpga_task.py`` requires following command-line arguments::
open_fpga_flow.py <task1_name> <task2_name> ... [<options>]
run_fpga_task.py <task1_name> <task2_name> ... [<options>]
where:
@ -58,6 +58,12 @@ Command-line Options
if any threads fail to execute successfully. It is mainly used to while
performing regression test.
.. option:: --default_tool_path
Specify the paths to tools as well as the keywords to extract QoR results from log files, when running this task. By default, the script will use the ``openfpga_flow/misc/fpgaflow_default_tool_path.conf``.
.. note:: Please use absolute path!!!
.. option:: --test_run
This option allows to debug OpenFPGA Task script

View File

@ -14,6 +14,14 @@ write_fabric_verilog
Specify the output directory for the Verilog netlists. For example, ``--file /temp/fabric_netlist/``
.. option:: --constant_undriven_inputs <string>
.. note:: This option is automatically enabled and set to ``bus0`` when the option ``perimeter_cb`` of tileable routing resource graph is enabled (see details in :ref`addon_vpr_syntax`).
.. note:: Enable this option may shadow issues in your FPGA architecture, which causes them difficult to be found in design verification.
Can be [``none`` | ``bus0`` | ``bus1`` | ``bit0`` | ``bit1`` ]. Use constant 0 or 1 for undriven wires in Verilog netlists. Recommand to enable when there are boundary routing tracks in FPGA fabric. When ``bus0`` or ``bus1`` are set, the constant wiring will be done in a bus format. When ``bit0`` or ``bit1`` are set, the constant wiring will be done in a bit-blast style. Suggest to use bit-blast style only when downstream Verilog parsers do not support bus format. By default, it is ``none``.
.. option:: --default_net_type <string>
Specify the default net type for the Verilog netlists. Currently, supported types are ``none`` and ``wire``. Default value: ``none``.
@ -61,6 +69,10 @@ write_full_testbench
The bitstream file to be loaded to the full testbench, which should be in the same file format that OpenFPGA can outputs (See detailes in :ref:`file_formats_fabric_bitstream_plain_text`). For example, ``--bitstream and2.bit``
.. option:: --simulator <string>
Specify the type of simulator which the full testbench will be used for. Currently support ``iverilog`` | ``vcs``. By default, assume the simulator is iverilog. For example, ``--simulator iverilog``. For different types of simulator, some syntax in the testbench may differ to help fast convergence.
.. option:: --fabric_netlist_file_path <string>
Specify the fabric Verilog file if they are not in the same directory as the testbenches to be generated. If not specified, OpenFPGA will assume that the fabric netlists are the in the same directory as testbenches and assign default names. For example, ``--file /temp/fabric/fabric_netlists.v``
@ -172,6 +184,10 @@ __ iverilog_website_
.. warning:: Signal initialization is only applied to the datapath inputs of routing multiplexers (considering the fact that they are indispensible cells of FPGAs)! If your FPGA does not contain any multiplexer cells, signal initialization is not applicable.
.. option:: --dump_waveform
Enable waveform output when runnign HDL simulation on the preconfigured wrapper. When enabled, waveform files can be outputted in two formats: ``fsdb`` and ``vcd`` through preprocessing flags ``DUMP_FSDB`` and ``DUMP_VCD`` respectively. For example, when using VCS,. the flag can be activiated by ``+define+DUMP_FSDB=1``.
.. option:: --no_time_stamp
Do not print time stamp in Verilog netlists

View File

@ -130,8 +130,17 @@ Clock signals will be auto-detected and routed based on pin constraints which ar
.. option:: --pin_constraints_file <string> or -pcf <string>
Specify the *Pin Constraints File* (PCF) when the clock network contains multiple clock pins. For example, ``-pin_constraints_file pin_constraints.xml``
Strongly recommend for multi-clock network. See detailed file format about :ref:`file_format_pin_constraints_file`.
Specify the *Pin Constraints File* (PCF) when the clock network contains multiple clock pins. For example, ``-pin_constraints_file pin_constraints.xml``. Strongly recommend for multi-clock network. See detailed file format about :ref:`file_format_pin_constraints_file`.
.. note:: If there is a global net, e.g., ``clk`` or ``reset``, which will be driven by an internal resource, it should also be defined in the PCF file.
.. option:: --disable_unused_trees
Disable entire clock trees when they are not used by any clock nets. Useful to reduce clock power
.. option:: --disable_unused_spines
Disable part of the clock tree which are used by clock nets. Useful to reduce clock power
.. option:: --verbose
@ -227,6 +236,10 @@ pb_pin_fixup
.. warning:: This command may be deprecated in future
.. option:: --map_global_net_to_msb
If specified, any global net including clock, reset etc, will be mapped to a best-fit Most Significant Bit (MSB) of input ports of programmable blocks. If not specified, a best-fit Least Significant Bit (LSB) will be the default choice. For example, when ``--clock_modeling ideal`` is selected when running VPR, global nets will not be routed and their pin mapping on programmable blocks may be revoked by other nets due to optimization. Therefore, this command will restore the pin mapping for the global nets and pick a spare pin on programmable blocks. This option is to set a preference when mapping the global nets to spare pins.
.. option:: --verbose
Show verbose log
@ -359,20 +372,33 @@ add_fpga_core_to_fabric
Show verbose log
.. _openfpga_setup_commands_write_fabric_hierarchy:
write_fabric_hierarchy
~~~~~~~~~~~~~~~~~~~~~~
Write the hierarchy of FPGA fabric graph to a plain-text file
Write the hierarchy of FPGA fabric graph to a YAML file
.. option:: --file <string> or -f <string>
Specify the file name to write the hierarchy.
Specify the file name to write the hierarchy. See details in :ref:`file_format_fabric_hierarchy_file`.
.. option:: --depth <int>
Specify at which depth of the fabric module graph should the writer stop outputting. The root module start from depth 0. For example, if you want a two-level hierarchy, you should specify depth as 1.
.. option:: --module <regexp>
Specify the root module name(s) which should be considered. By default, it is ``fpga_top``. Note that regular expression is supported. For example, ``grid_*`` will output all the modules with a prefix of ``grid_``
.. option:: --filter <regexp>
Specify the filter which allows user to select modules to appear under each root module tree. By default, it is ``*``. Regular expression is supported. For example, ``*mux*`` will output all the modules which contains ``mux``. In the other words, the filter defines a white list.
.. option:: --exclude_empty_modules
Exclude modules with no qualified children (match the names defined through filter) from the output file
.. option:: --verbose
Show verbose log
@ -392,7 +418,7 @@ write_fabric_io_info
.. option:: --no_time_stamp
Do not print time stamp in bitstream files
Do not print time stamp in output files
.. option:: --verbose
@ -433,7 +459,7 @@ pcf2place
.. option:: --no_time_stamp
Do not print time stamp in bitstream files
Do not print time stamp in output files
.. option:: --verbose
@ -467,8 +493,98 @@ write_module_naming_rules
.. option:: --no_time_stamp
Do not print time stamp in bitstream files
Do not print time stamp in output files
.. option:: --verbose
Show verbose log
.. _openfpga_setup_commands_write_fabric_pin_physical_location:
write_fabric_pin_physical_location
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Output the physical location of each pin for each module of an FPGA fabric to a given file
.. option:: --file <string>
Specify the file path to be written to. See details in :ref:`file_format_fabric_pin_physical_location_file`.
.. option:: --module <string>
Specify the name of modules to be considered. Support regular expression, e.g., ``tile*``. When provided, only pins of selected modules will be outputted. By default, a wildcard ``*`` is considered, which means all the modules will be considered.
.. option:: --show_invalid_side
Show sides for each pin, even these pin does not have a specific valid side. This is mainly used for debugging.
.. option:: --no_time_stamp
Do not print time stamp in output files
.. option:: --verbose
Show verbose log
.. _openfpga_setup_commands_report_reference:
report_reference
~~~~~~~~~~~~~~~~~~~~
Write reference information of each child module under a given parent module to a YAML file
.. option:: --file <string> or -f <string>
Specify the file name to write the reference information. See details in :ref:`file_format_reference_file`.
.. option:: --module <string>
Specify the parent module name, under which the references of each child module will be reported.
.. option:: --no_time_stamp
Do not print time stamp in output files
.. option:: --verbose
Show verbose info
.. _openfpga_setup_commands_read_unique_blocks:
read_unique_blocks
~~~~~~~~~~~~~~~~~~~~
Read information of unique blocks from a given file.
.. option:: --file <string>
Specify the file which contains unique block information. See details in :ref:`file_formats_unique_blocks`.
.. option:: --type <string>
Specify the type of the unique blocks file [xml|bin]. If not specified, by default it is XML.
.. option:: --verbose
Show verbose info
.. _openfpga_setup_commands_write_unique_blocks:
write_unique_blocks
~~~~~~~~~~~~~~~~~~~~~
Write information of unique blocks from internal data structure to a given file.
.. option:: --file <string>
Specify the file which we will write unique block information to. See details in :ref:`file_formats_unique_blocks`.
.. option:: --type <string>
Specify the type of the unique blocks file [xml|bin]. If not specified, by default it is XML.
.. option:: --verbose
Show verbose info

View File

@ -12,7 +12,7 @@ How to Compile
Supported Operating Systems
~~~~~~~~~~~~~~~~~~~~~~~~~~~
OpenFPGA is continously tested with Ubuntu 20.04 and partially on Ubuntu 22.04
OpenFPGA is continously tested with Ubuntu 22.04 and partially on Ubuntu 20.04
It might work with earlier versions and other distributions.
In addition to continous integration, our community users have tested OpenFPGA on their local machines using the following operating systems:
@ -21,7 +21,6 @@ In addition to continous integration, our community users have tested OpenFPGA o
- CentOS 8
- Ubuntu 18.04
- Ubuntu 21.04
- Ubuntu 22.04
Build Steps
~~~~~~~~~~~
@ -34,7 +33,7 @@ In general, please follow the steps to compile
cd OpenFPGA
make all
.. note:: OpenFPGA requires gcc/g++ version > 7 and clang version > 6.
.. note:: OpenFPGA requires gcc/g++ version > 9 and clang version > 10.
.. note:: cmake3.12+ is recommended to compile OpenFPGA with GUI
@ -111,7 +110,7 @@ Ubuntu 20.04
- Dependencies required to run regression tests
.. include:: regtest_dependencies.sh
.. include:: ubuntu20p04_regtest_dependencies.sh
:code: shell
.. note:: Python packages are also required
@ -135,7 +134,7 @@ Ubuntu 22.04
- Dependencies required to run regression tests
.. include:: regtest_dependencies.sh
.. include:: ubuntu22p04_regtest_dependencies.sh
:code: shell
.. note:: Python packages are also required

View File

@ -1 +1 @@
../../../../.github/workflows/install_dependencies_run.sh
../../../../.github/workflows/install_dependencies_run_ubuntu22p04.sh

View File

@ -1 +1 @@
../../../../.github/workflows/install_dependencies_build.sh
../../../../.github/workflows/install_dependencies_build_ubuntu20p04.sh

View File

@ -0,0 +1 @@
../../../../.github/workflows/install_dependencies_run_ubuntu20p04.sh

View File

@ -0,0 +1 @@
../../../../.github/workflows/install_dependencies_run_ubuntu22p04.sh

View File

@ -10,3 +10,4 @@ add_subdirectory(libpcf)
add_subdirectory(libbusgroup)
add_subdirectory(libnamemanager)
add_subdirectory(libtileconfig)
add_subdirectory(libopenfpgacapnproto)

View File

@ -71,7 +71,7 @@ ArchDirectId ArchDirect::add_direct(const std::string& name) {
direct_ids_.push_back(direct);
names_.push_back(name);
circuit_models_.push_back(CircuitModelId::INVALID());
types_.emplace_back(NUM_DIRECT_TYPES);
types_.emplace_back(e_direct_type::NUM_DIRECT_TYPES);
directions_.emplace_back(vtr::Point<e_direct_direction>(
NUM_DIRECT_DIRECTIONS, NUM_DIRECT_DIRECTIONS));

View File

@ -14,15 +14,16 @@
* These types are supplementary to the original VPR direct connections
* Here we extend to the cross-row and cross-column connections
********************************************************************/
enum e_direct_type {
INNER_COLUMN,
INNER_ROW,
enum class e_direct_type {
INNER_COLUMN_OR_ROW,
PART_OF_CB,
INTER_COLUMN,
INTER_ROW,
NUM_DIRECT_TYPES
};
constexpr std::array<const char*, NUM_DIRECT_TYPES> DIRECT_TYPE_STRING = {
{"inner_column", "inner_row", "inter_column", "inter_row"}};
constexpr std::array<const char*, (size_t)e_direct_type::NUM_DIRECT_TYPES>
DIRECT_TYPE_STRING = {
{"inner_column_or_row", "part_of_cb", "inter_column", "inter_row"}};
enum e_direct_direction { POSITIVE_DIR, NEGATIVE_DIR, NUM_DIRECT_DIRECTIONS };
constexpr std::array<const char*, NUM_DIRECT_DIRECTIONS>

View File

@ -24,6 +24,12 @@ BitstreamSetting::interconnect_settings() const {
interconnect_setting_ids_.end());
}
BitstreamSetting::overwrite_bitstream_range
BitstreamSetting::overwrite_bitstreams() const {
return vtr::make_range(overwrite_bitstream_ids_.begin(),
overwrite_bitstream_ids_.end());
}
/************************************************************************
* Constructors
***********************************************************************/
@ -102,6 +108,22 @@ std::string BitstreamSetting::default_path(
return interconnect_default_paths_[interconnect_setting_id];
}
std::vector<NonFabricBitstreamSetting> BitstreamSetting::non_fabric() const {
return non_fabric_;
}
std::string BitstreamSetting::overwrite_bitstream_path(
const OverwriteBitstreamId& id) const {
VTR_ASSERT(true == valid_overwrite_bitstream_id(id));
return overwrite_bitstream_paths_[id];
}
bool BitstreamSetting::overwrite_bitstream_value(
const OverwriteBitstreamId& id) const {
VTR_ASSERT(true == valid_overwrite_bitstream_id(id));
return overwrite_bitstream_values_[id];
}
/************************************************************************
* Public Mutators
***********************************************************************/
@ -154,6 +176,41 @@ BitstreamSetting::add_bitstream_interconnect_setting(
return interc_setting_id;
}
void BitstreamSetting::add_non_fabric(const std::string& name,
const std::string& file) {
VTR_ASSERT(name.size());
VTR_ASSERT(file.size());
non_fabric_.push_back(NonFabricBitstreamSetting(name, file));
}
void BitstreamSetting::add_non_fabric_pb(const std::string& pb,
const std::string& content) {
VTR_ASSERT(non_fabric_.size());
VTR_ASSERT(content.find(".param ") == 0 || content.find(".attr ") == 0);
if (content.find(".param ") == 0) {
VTR_ASSERT(content.size() > 7);
non_fabric_.back().add_pb(pb, "param", content.substr(7));
} else {
VTR_ASSERT(content.size() > 6);
non_fabric_.back().add_pb(pb, "attr", content.substr(6));
}
}
OverwriteBitstreamId BitstreamSetting::add_overwrite_bitstream(
const std::string& path, const bool& value) {
VTR_ASSERT(path.size());
VTR_ASSERT(overwrite_bitstream_ids_.size() ==
overwrite_bitstream_paths_.size());
VTR_ASSERT(overwrite_bitstream_paths_.size() ==
overwrite_bitstream_values_.size());
OverwriteBitstreamId id =
OverwriteBitstreamId(overwrite_bitstream_ids_.size());
overwrite_bitstream_ids_.push_back(id);
overwrite_bitstream_paths_.push_back(path);
overwrite_bitstream_values_.push_back(value);
return id;
}
/************************************************************************
* Public Validators
***********************************************************************/
@ -170,4 +227,14 @@ bool BitstreamSetting::valid_bitstream_interconnect_setting_id(
interconnect_setting_ids_[interconnect_setting_id]);
}
bool BitstreamSetting::valid_overwrite_bitstream_id(
const OverwriteBitstreamId& id) const {
VTR_ASSERT(overwrite_bitstream_ids_.size() ==
overwrite_bitstream_paths_.size());
VTR_ASSERT(overwrite_bitstream_paths_.size() ==
overwrite_bitstream_values_.size());
return (size_t(id) < overwrite_bitstream_ids_.size()) &&
(id == overwrite_bitstream_ids_[id]);
}
} // namespace openfpga

View File

@ -6,6 +6,7 @@
* which are used by OpenFPGA
*******************************************************************/
#include <string>
#include <vector>
#include "bitstream_setting_fwd.h"
#include "vtr_vector.h"
@ -13,6 +14,29 @@
/* namespace openfpga begins */
namespace openfpga {
struct NonFabricBitstreamPBSetting {
NonFabricBitstreamPBSetting(const std::string& p = "",
const std::string& t = "",
const std::string& c = "")
: pb(p), type(t), content(c) {}
const std::string pb = "";
const std::string type = "";
const std::string content = "";
};
struct NonFabricBitstreamSetting {
NonFabricBitstreamSetting(const std::string& n = "",
const std::string& f = "")
: name(n), file(f) {}
void add_pb(const std::string& p, const std::string& t,
const std::string& c) {
pbs.push_back(NonFabricBitstreamPBSetting(p, t, c));
}
const std::string name = "";
const std::string file = "";
std::vector<NonFabricBitstreamPBSetting> pbs;
};
/********************************************************************
* A data structure to describe bitstream settings
*
@ -37,11 +61,15 @@ class BitstreamSetting {
typedef vtr::vector<BitstreamInterconnectSettingId,
BitstreamInterconnectSettingId>::const_iterator
bitstream_interconnect_setting_iterator;
typedef vtr::vector<OverwriteBitstreamId,
OverwriteBitstreamId>::const_iterator
overwrite_bitstream_iterator;
/* Create range */
typedef vtr::Range<bitstream_pb_type_setting_iterator>
bitstream_pb_type_setting_range;
typedef vtr::Range<bitstream_interconnect_setting_iterator>
bitstream_interconnect_setting_range;
typedef vtr::Range<overwrite_bitstream_iterator> overwrite_bitstream_range;
public: /* Constructors */
BitstreamSetting();
@ -49,6 +77,7 @@ class BitstreamSetting {
public: /* Accessors: aggregates */
bitstream_pb_type_setting_range pb_type_settings() const;
bitstream_interconnect_setting_range interconnect_settings() const;
overwrite_bitstream_range overwrite_bitstreams() const;
public: /* Public Accessors */
std::string pb_type_name(
@ -73,6 +102,9 @@ class BitstreamSetting {
const BitstreamInterconnectSettingId& interconnect_setting_id) const;
std::string default_path(
const BitstreamInterconnectSettingId& interconnect_setting_id) const;
std::vector<NonFabricBitstreamSetting> non_fabric() const;
std::string overwrite_bitstream_path(const OverwriteBitstreamId& id) const;
bool overwrite_bitstream_value(const OverwriteBitstreamId& id) const;
public: /* Public Mutators */
BitstreamPbTypeSettingId add_bitstream_pb_type_setting(
@ -92,11 +124,18 @@ class BitstreamSetting {
const std::vector<std::string>& parent_mode_names,
const std::string& default_path);
void add_non_fabric(const std::string& name, const std::string& file);
void add_non_fabric_pb(const std::string& pb, const std::string& content);
OverwriteBitstreamId add_overwrite_bitstream(const std::string& path,
const bool& value);
public: /* Public Validators */
bool valid_bitstream_pb_type_setting_id(
const BitstreamPbTypeSettingId& pb_type_setting_id) const;
bool valid_bitstream_interconnect_setting_id(
const BitstreamInterconnectSettingId& interconnect_setting_id) const;
bool valid_overwrite_bitstream_id(const OverwriteBitstreamId& id) const;
private: /* Internal data */
/* Pb type -related settings
@ -133,6 +172,11 @@ class BitstreamSetting {
interconnect_parent_mode_names_;
vtr::vector<BitstreamInterconnectSettingId, std::string>
interconnect_default_paths_;
std::vector<NonFabricBitstreamSetting> non_fabric_;
vtr::vector<OverwriteBitstreamId, OverwriteBitstreamId>
overwrite_bitstream_ids_;
vtr::vector<OverwriteBitstreamId, std::string> overwrite_bitstream_paths_;
vtr::vector<OverwriteBitstreamId, bool> overwrite_bitstream_values_;
};
} // namespace openfpga

View File

@ -15,11 +15,13 @@
struct bitstream_pb_type_setting_id_tag;
struct bitstream_interconnect_setting_id_tag;
struct overwrite_bitstream_id_tag;
typedef vtr::StrongId<bitstream_pb_type_setting_id_tag>
BitstreamPbTypeSettingId;
typedef vtr::StrongId<bitstream_interconnect_setting_id_tag>
BitstreamInterconnectSettingId;
typedef vtr::StrongId<overwrite_bitstream_id_tag> OverwriteBitstreamId;
/* Short declaration of class */
class BitstreamSetting;

View File

@ -800,6 +800,60 @@ static size_t check_io_circuit_model(const CircuitLibrary& circuit_lib) {
return num_err;
}
/************************************************************************
* Check the last stage pass gate logic model is the same type as default
***********************************************************************/
static size_t check_pass_gate_circuit_model_consistency(
const CircuitLibrary& circuit_lib) {
size_t num_err = 0;
for (const CircuitModelId& mux_model :
circuit_lib.models_by_type(CIRCUIT_MODEL_MUX)) {
CircuitModelId pgl_model = circuit_lib.pass_gate_logic_model(mux_model);
CircuitModelId last_stage_pgl_model =
circuit_lib.last_stage_pass_gate_logic_model(mux_model);
if (!circuit_lib.valid_model_id(pgl_model)) {
VTR_LOGF_ERROR(
__FILE__, __LINE__,
"The pass-gate logic circuit model '%s' of '%s' is not valid!\n",
circuit_lib.pass_gate_logic_model_name(mux_model).c_str(),
circuit_lib.model_name(mux_model).c_str());
num_err++;
}
if (!circuit_lib.valid_model_id(last_stage_pgl_model)) {
VTR_LOGF_ERROR(
__FILE__, __LINE__,
"The last stage pass-gate logic circuit model '%s' of '%s' is not "
"valid!\n",
circuit_lib.last_stage_pass_gate_logic_model_name(mux_model).c_str(),
circuit_lib.model_name(mux_model).c_str());
num_err++;
}
if (circuit_lib.model_type(pgl_model) !=
circuit_lib.model_type(last_stage_pgl_model)) {
VTR_LOGF_ERROR(
__FILE__, __LINE__,
"The last stage pass-gate logic circuit model '%s' of '%s' should be "
"the same type as its regular pass-gate logic model '%s'!\n",
circuit_lib.model_name(last_stage_pgl_model).c_str(),
circuit_lib.model_name(mux_model).c_str(),
circuit_lib.model_name(pgl_model).c_str());
num_err++;
}
if (pgl_model != last_stage_pgl_model &&
circuit_lib.gate_type(pgl_model) != CIRCUIT_MODEL_GATE_MUX2) {
VTR_LOGF_ERROR(__FILE__, __LINE__,
"The last stage pass-gate logic circuit model '%s' of "
"'%s' should be a MUX2 gate!\n",
circuit_lib.model_name(last_stage_pgl_model).c_str(),
circuit_lib.model_name(mux_model).c_str());
num_err++;
}
}
return num_err;
}
/************************************************************************
* Check points to make sure we have a valid circuit library
* Detailed checkpoints:
@ -920,6 +974,9 @@ bool check_circuit_library(const CircuitLibrary& circuit_lib) {
/* 11. Check power-gated inverter/buffer models */
num_err += check_power_gated_circuit_models(circuit_lib);
/* 12. Check pass-gate logic model consistency */
num_err += check_pass_gate_circuit_model_consistency(circuit_lib);
/* If we have any errors, exit */
if (0 < num_err) {

View File

@ -259,6 +259,28 @@ CircuitModelId CircuitLibrary::pass_gate_logic_model(
return pgl_model_id;
}
/* Find the id of pass-gate circuit model
* Two cases to be considered:
* 1. this is a pass-gate circuit model, just find the data and return
* 2. this circuit model includes a pass-gate, find the link to pass-gate
* circuit model and go recursively
*/
CircuitModelId CircuitLibrary::last_stage_pass_gate_logic_model(
const CircuitModelId& model_id) const {
/* validate the model_id */
VTR_ASSERT(valid_model_id(model_id));
/* Return the data if this is a pass-gate circuit model */
if (CIRCUIT_MODEL_PASSGATE == model_type(model_id)) {
return model_ids_[model_id];
}
/* Otherwise, we need to make sure this circuit model contains a pass-gate */
CircuitModelId pgl_model_id = last_stage_pass_gate_logic_model_ids_[model_id];
VTR_ASSERT(CircuitModelId::INVALID() != pgl_model_id);
return pgl_model_id;
}
/* Find the name of pass-gate circuit model
* Two cases to be considered:
* 1. this is a pass-gate circuit model, just find the data and return
@ -279,6 +301,26 @@ std::string CircuitLibrary::pass_gate_logic_model_name(
return pass_gate_logic_model_names_[model_id];
}
/* Find the name of pass-gate circuit model
* Two cases to be considered:
* 1. this is a pass-gate circuit model, just find the data and return
* 2. this circuit model includes a pass-gate, find the link to pass-gate
* circuit model and go recursively
*/
std::string CircuitLibrary::last_stage_pass_gate_logic_model_name(
const CircuitModelId& model_id) const {
/* validate the model_id */
VTR_ASSERT(valid_model_id(model_id));
/* Return the data if this is a pass-gate circuit model */
if (CIRCUIT_MODEL_PASSGATE == model_type(model_id)) {
return model_names_[model_id];
}
/* Otherwise, we need to make sure this circuit model contains a pass-gate */
return last_stage_pass_gate_logic_model_names_[model_id];
}
/* Return the type of pass gate logic module, only applicable to circuit model
* whose type is pass-gate logic */
enum e_circuit_model_pass_gate_logic_type CircuitLibrary::pass_gate_logic_type(
@ -1262,6 +1304,8 @@ CircuitModelId CircuitLibrary::add_model(
/* Pass-gate-related parameters */
pass_gate_logic_model_names_.emplace_back();
pass_gate_logic_model_ids_.emplace_back(CircuitModelId::INVALID());
last_stage_pass_gate_logic_model_names_.emplace_back();
last_stage_pass_gate_logic_model_ids_.emplace_back(CircuitModelId::INVALID());
/* Delay information */
delay_types_.emplace_back();
@ -1485,6 +1529,15 @@ void CircuitLibrary::set_model_pass_gate_logic(const CircuitModelId& model_id,
return;
}
/* Set pass-gate logic information of a circuit model */
void CircuitLibrary::set_model_last_stage_pass_gate_logic(
const CircuitModelId& model_id, const std::string& model_name) {
/* validate the model_id */
VTR_ASSERT(valid_model_id(model_id));
last_stage_pass_gate_logic_model_names_[model_id] = model_name;
return;
}
/* Add a port to a circuit model */
CircuitPortId CircuitLibrary::add_model_port(
const CircuitModelId& model_id,
@ -2174,6 +2227,12 @@ void CircuitLibrary::link_pass_gate_logic_model(
}
pass_gate_logic_model_ids_[model_id] =
model(pass_gate_logic_model_names_[model_id]);
/* Get the circuit model id by name, skip those with empty names*/
if (true == last_stage_pass_gate_logic_model_names_[model_id].empty()) {
return;
}
last_stage_pass_gate_logic_model_ids_[model_id] =
model(last_stage_pass_gate_logic_model_names_[model_id]);
return;
}

View File

@ -272,7 +272,11 @@ class CircuitLibrary {
const CircuitModelId& model_id) const;
/* Pass-gate-logic information */
CircuitModelId pass_gate_logic_model(const CircuitModelId& model_id) const;
CircuitModelId last_stage_pass_gate_logic_model(
const CircuitModelId& model_id) const;
std::string pass_gate_logic_model_name(const CircuitModelId& model_id) const;
std::string last_stage_pass_gate_logic_model_name(
const CircuitModelId& model_id) const;
enum e_circuit_model_pass_gate_logic_type pass_gate_logic_type(
const CircuitModelId& model_id) const;
float pass_gate_logic_pmos_size(const CircuitModelId& model_id) const;
@ -448,6 +452,8 @@ class CircuitLibrary {
/* Pass-gate-related parameters */
void set_model_pass_gate_logic(const CircuitModelId& model_id,
const std::string& model_name);
void set_model_last_stage_pass_gate_logic(const CircuitModelId& model_id,
const std::string& model_name);
/* Port information */
CircuitPortId add_model_port(const CircuitModelId& model_id,
const enum e_circuit_model_port_type& port_type);
@ -664,6 +670,10 @@ class CircuitLibrary {
/* Pass-gate-related parameters */
vtr::vector<CircuitModelId, std::string> pass_gate_logic_model_names_;
vtr::vector<CircuitModelId, CircuitModelId> pass_gate_logic_model_ids_;
vtr::vector<CircuitModelId, std::string>
last_stage_pass_gate_logic_model_names_;
vtr::vector<CircuitModelId, CircuitModelId>
last_stage_pass_gate_logic_model_ids_;
/* Port information */
vtr::vector<CircuitPortId, CircuitPortId> port_ids_;

View File

@ -116,6 +116,11 @@ CircuitModelId ConfigProtocol::wl_memory_model() const {
size_t ConfigProtocol::wl_num_banks() const { return wl_num_banks_; }
const QLMemoryBankConfigSetting* ConfigProtocol::ql_memory_bank_config_setting()
const {
return &ql_memory_bank_config_setting_;
}
/************************************************************************
* Public Mutators
***********************************************************************/
@ -256,6 +261,10 @@ void ConfigProtocol::set_wl_num_banks(const size_t& num_banks) {
wl_num_banks_ = num_banks;
}
QLMemoryBankConfigSetting* ConfigProtocol::get_ql_memory_bank_config_setting() {
return &ql_memory_bank_config_setting_;
}
/************************************************************************
* Private Validators
***********************************************************************/

View File

@ -7,6 +7,7 @@
#include "circuit_library_fwd.h"
#include "circuit_types.h"
#include "openfpga_port.h"
#include "ql_memory_bank_config_setting.h"
/* Data type to define the protocol through which BL/WL can be manipulated */
enum e_blwl_protocol_type {
@ -54,6 +55,9 @@ class ConfigProtocol {
CircuitModelId wl_memory_model() const;
size_t wl_num_banks() const;
/* QL Memory Bank Config Setting */
const QLMemoryBankConfigSetting* ql_memory_bank_config_setting() const;
public: /* Public Mutators */
void set_type(const e_config_protocol_type& type);
void set_memory_model_name(const std::string& memory_model_name);
@ -76,6 +80,9 @@ class ConfigProtocol {
void set_wl_memory_model(const CircuitModelId& memory_model);
void set_wl_num_banks(const size_t& num_banks);
/* QL Memory Bank Config Setting */
QLMemoryBankConfigSetting* get_ql_memory_bank_config_setting();
public: /* Public validators */
/* Check if internal data has any conflicts to each other. Return number of
* errors detected */
@ -131,6 +138,9 @@ class ConfigProtocol {
std::string wl_memory_model_name_;
CircuitModelId wl_memory_model_;
size_t wl_num_banks_;
/* QL Memory Bank Config Setting */
QLMemoryBankConfigSetting ql_memory_bank_config_setting_;
};
#endif

View File

@ -0,0 +1,34 @@
#include "ql_memory_bank_config_setting.h"
#include "openfpga_tokenizer.h"
#include "vtr_assert.h"
#include "vtr_log.h"
/************************************************************************
* Member functions for class QLMemoryBankConfigSetting
***********************************************************************/
/************************************************************************
* Constructors
***********************************************************************/
QLMemoryBankConfigSetting::QLMemoryBankConfigSetting() {}
/************************************************************************
* Public Accessors
***********************************************************************/
QLMemoryBankPBSetting QLMemoryBankConfigSetting::pb_setting(
const std::string& name) const {
if (settings_.find(name) != settings_.end()) {
return settings_.at(name);
}
return QLMemoryBankPBSetting();
}
/************************************************************************
* Public Mutators
***********************************************************************/
void QLMemoryBankConfigSetting::add_pb_setting(const std::string& name,
uint32_t num_wl) {
VTR_ASSERT(settings_.find(name) == settings_.end());
settings_[name] = QLMemoryBankPBSetting(num_wl);
}

View File

@ -0,0 +1,30 @@
#ifndef QL_MEMORY_BANK_CONFIG_SETTING_H
#define QL_MEMORY_BANK_CONFIG_SETTING_H
#include <cstdint>
#include <map>
#include <string>
struct QLMemoryBankPBSetting {
QLMemoryBankPBSetting(uint32_t n = 0) : num_wl(n) {}
uint32_t num_wl = 0;
};
/********************************************************************
* A data structure to store QL Memory Bank configuration setting
*******************************************************************/
class QLMemoryBankConfigSetting {
public: /* Constructors */
QLMemoryBankConfigSetting();
public: /* Public Accessors */
QLMemoryBankPBSetting pb_setting(const std::string& name) const;
public: /* Public Mutators */
void add_pb_setting(const std::string& name, uint32_t num_wl);
private: /* Internal data */
std::map<std::string, QLMemoryBankPBSetting> settings_;
};
#endif

View File

@ -76,6 +76,56 @@ static void read_xml_bitstream_interconnect_setting(
operating_pb_parser.modes(), default_path_attr);
}
/********************************************************************
* Parse XML description for a non_fabric annotation under a <non_fabric> XML
*node
*******************************************************************/
static void read_xml_non_fabric_bitstream_setting(
pugi::xml_node& xml_non_fabric, const pugiutil::loc_data& loc_data,
openfpga::BitstreamSetting& bitstream_setting) {
const std::string& name_attr =
get_attribute(xml_non_fabric, "name", loc_data).as_string();
const std::string& file_attr =
get_attribute(xml_non_fabric, "file", loc_data).as_string();
/* Add to non-fabric */
bitstream_setting.add_non_fabric(name_attr, file_attr);
for (pugi::xml_node xml_child : xml_non_fabric.children()) {
if (xml_child.name() != std::string("pb")) {
bad_tag(xml_child, loc_data, xml_non_fabric, {"pb"});
}
const std::string& pb_name_attr =
get_attribute(xml_child, "name", loc_data).as_string();
const std::string& content_attr =
get_attribute(xml_child, "content", loc_data).as_string();
/* Add PB to non-fabric */
bitstream_setting.add_non_fabric_pb(pb_name_attr, content_attr);
}
}
/********************************************************************
* Parse XML description for a bit setting under a <bit> XML node
*******************************************************************/
static void read_xml_overwrite_bitstream_setting(
pugi::xml_node& xml_overwrite_bitstream, const pugiutil::loc_data& loc_data,
openfpga::BitstreamSetting& bitstream_setting) {
// Loopthrough bit
for (pugi::xml_node xml_bit : xml_overwrite_bitstream.children()) {
if (xml_bit.name() != std::string("bit")) {
bad_tag(xml_bit, loc_data, xml_overwrite_bitstream, {"bit"});
}
const std::string& path_attr =
get_attribute(xml_bit, "path", loc_data).as_string();
const std::string& value_attr =
get_attribute(xml_bit, "value", loc_data).as_string();
if (value_attr != "0" && value_attr != "1") {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_bit),
"Invalid value of overwrite_bitstream bit. Expect [0|1]");
}
/* Add to bit */
bitstream_setting.add_overwrite_bitstream(path_attr, value_attr == "1");
}
}
/********************************************************************
* Parse XML codes about <openfpga_bitstream_setting> to an object
*******************************************************************/
@ -89,17 +139,26 @@ openfpga::BitstreamSetting read_xml_bitstream_setting(
for (pugi::xml_node xml_child : Node.children()) {
/* Error out if the XML child has an invalid name! */
if ((xml_child.name() != std::string("pb_type")) &&
(xml_child.name() != std::string("interconnect"))) {
bad_tag(xml_child, loc_data, Node, {"pb_type | interconnect"});
(xml_child.name() != std::string("interconnect")) &&
(xml_child.name() != std::string("non_fabric")) &&
(xml_child.name() != std::string("overwrite_bitstream"))) {
bad_tag(xml_child, loc_data, Node,
{"pb_type | interconnect | non_fabric | overwrite_bitstream"});
}
if (xml_child.name() == std::string("pb_type")) {
read_xml_bitstream_pb_type_setting(xml_child, loc_data,
bitstream_setting);
} else {
VTR_ASSERT_SAFE(xml_child.name() == std::string("interconnect"));
} else if (xml_child.name() == std::string("interconnect")) {
read_xml_bitstream_interconnect_setting(xml_child, loc_data,
bitstream_setting);
} else if (xml_child.name() == std::string("non_fabric")) {
read_xml_non_fabric_bitstream_setting(xml_child, loc_data,
bitstream_setting);
} else {
VTR_ASSERT_SAFE(xml_child.name() == std::string("overwrite_bitstream"));
read_xml_overwrite_bitstream_setting(xml_child, loc_data,
bitstream_setting);
}
}

View File

@ -832,6 +832,25 @@ static void read_xml_circuit_model(pugi::xml_node& xml_model,
circuit_lib.set_model_pass_gate_logic(
model, get_attribute(xml_pass_gate_logic, "circuit_model_name", loc_data)
.as_string());
/* Last stage pass gate is optional */
size_t num_last_stage_pgl =
count_children(xml_model, "last_stage_pass_gate_logic", loc_data,
pugiutil::ReqOpt::OPTIONAL);
if (0 < num_last_stage_pgl) {
auto xml_last_stage_pass_gate_logic =
get_single_child(xml_model, "last_stage_pass_gate_logic", loc_data);
circuit_lib.set_model_last_stage_pass_gate_logic(
model, get_attribute(xml_last_stage_pass_gate_logic,
"circuit_model_name", loc_data)
.as_string());
} else {
/* By default, assume the last stage circuit model is the same as others
*/
circuit_lib.set_model_last_stage_pass_gate_logic(
model,
get_attribute(xml_pass_gate_logic, "circuit_model_name", loc_data)
.as_string());
}
}
/* Parse all the ports belonging to this circuit model

View File

@ -249,6 +249,32 @@ static void read_xml_config_organization(pugi::xml_node& xml_config_orgz,
}
}
/********************************************************************
* Parse XML codes about <ql_memory_bank_config_setting> to
*QLMemoryBankConfigSetting
*******************************************************************/
static void read_xml_ql_memory_bank_config_setting(
QLMemoryBankConfigSetting* setting, pugi::xml_node& Node,
const pugiutil::loc_data& loc_data) {
/* Parse configuration protocol root node */
pugi::xml_node config_setting =
get_single_child(Node, "ql_memory_bank_config_setting", loc_data,
pugiutil::ReqOpt::OPTIONAL);
if (config_setting) {
/* Add to ql_memory_bank_config_setting_ */
for (pugi::xml_node xml_child : config_setting.children()) {
if (xml_child.name() != std::string("pb_type")) {
bad_tag(xml_child, loc_data, config_setting, {"pb_type"});
}
const std::string& name_attr =
get_attribute(xml_child, "name", loc_data).as_string();
uint32_t num_wl = get_attribute(xml_child, "num_wl", loc_data).as_uint();
setting->add_pb_setting(name_attr, num_wl);
}
}
}
/********************************************************************
* Parse XML codes about <configuration_protocol> to an object of ConfigProtocol
*******************************************************************/
@ -264,5 +290,14 @@ ConfigProtocol read_xml_config_protocol(pugi::xml_node& Node,
get_single_child(xml_config, "organization", loc_data);
read_xml_config_organization(xml_config_orgz, loc_data, config_protocol);
/* Parse QL Memory Bank configuration setting */
if (config_protocol.type() == CONFIG_MEM_QL_MEMORY_BANK &&
config_protocol.bl_protocol_type() == BLWL_PROTOCOL_FLATTEN &&
config_protocol.wl_protocol_type() == BLWL_PROTOCOL_FLATTEN) {
read_xml_ql_memory_bank_config_setting(
config_protocol.get_ql_memory_bank_config_setting(), xml_config,
loc_data);
}
return config_protocol;
}

View File

@ -11,6 +11,7 @@
/* Headers from vtr util library */
#include "vtr_assert.h"
#include "vtr_log.h"
/* Headers from libarchfpga */
#include "arch_error.h"
@ -198,15 +199,20 @@ std::map<std::string, CircuitModelId> read_xml_routing_segment_circuit(
* Convert string to the enumerate of direct type
*******************************************************************/
static e_direct_type string_to_direct_type(const std::string& type_string) {
if (std::string("column") == type_string) {
return INTER_COLUMN;
if (std::string("part_of_cb") == type_string) {
return e_direct_type::PART_OF_CB;
}
if (std::string("inner_column_or_row") == type_string) {
return e_direct_type::INNER_COLUMN_OR_ROW;
}
if (std::string("inter_column") == type_string) {
return e_direct_type::INTER_COLUMN;
}
if (std::string("inter_row") == type_string) {
return e_direct_type::INTER_ROW;
}
if (std::string("row") == type_string) {
return INTER_ROW;
}
return NUM_DIRECT_TYPES;
return e_direct_type::NUM_DIRECT_TYPES;
}
/********************************************************************
@ -255,13 +261,6 @@ ArchDirect read_xml_direct_circuit(pugi::xml_node& Node,
std::string direct_name =
get_attribute(xml_direct, "name", loc_data).as_string();
/* Get the routing segment circuit model name */
std::string direct_model_name =
get_attribute(xml_direct, "circuit_model_name", loc_data).as_string();
CircuitModelId direct_model = find_routing_circuit_model(
xml_direct, loc_data, circuit_lib, direct_model_name, CIRCUIT_MODEL_WIRE);
/* Add to the Arch direct database */
ArchDirectId direct = arch_direct.add_direct(direct_name);
if (false == arch_direct.valid_direct_id(direct)) {
@ -269,28 +268,48 @@ ArchDirect read_xml_direct_circuit(pugi::xml_node& Node,
"Direct name '%s' has been defined more than once!\n",
direct_name.c_str());
}
arch_direct.set_circuit_model(direct, direct_model);
/* Add more information*/
std::string direct_type_name =
get_attribute(xml_direct, "type", loc_data, pugiutil::ReqOpt::OPTIONAL)
.as_string("none");
/* If not defined, we go to the next */
if (std::string("none") == direct_type_name) {
continue;
}
.as_string(
DIRECT_TYPE_STRING[size_t(e_direct_type::INNER_COLUMN_OR_ROW)]);
e_direct_type direct_type = string_to_direct_type(direct_type_name);
if (NUM_DIRECT_TYPES == direct_type) {
if (e_direct_type::NUM_DIRECT_TYPES == direct_type) {
archfpga_throw(
loc_data.filename_c_str(), loc_data.line(xml_direct),
"Direct type '%s' is not support! Acceptable values are [column|row]\n",
"Direct type '%s' is not support! Acceptable values are "
"[inner_column_or_row|part_of_cb|inter_column|inter_row]\n",
direct_type_name.c_str());
}
arch_direct.set_type(direct, direct_type);
/* Get the routing segment circuit model name */
std::string direct_model_name =
get_attribute(xml_direct, "circuit_model_name", loc_data).as_string();
/* If a direct connection is part of a connection block, the circuit model
* should be a MUX */
e_circuit_model_type expected_circuit_model_type = CIRCUIT_MODEL_WIRE;
if (arch_direct.type(direct) == e_direct_type::PART_OF_CB) {
VTR_LOG("Direct '%s' will modelled as part of a connection block.\n",
direct_name.c_str());
expected_circuit_model_type = CIRCUIT_MODEL_MUX;
}
CircuitModelId direct_model = find_routing_circuit_model(
xml_direct, loc_data, circuit_lib, direct_model_name,
expected_circuit_model_type);
arch_direct.set_circuit_model(direct, direct_model);
/* The following syntax is only available for inter-column/row */
if (arch_direct.type(direct) != e_direct_type::INTER_COLUMN &&
arch_direct.type(direct) != e_direct_type::INTER_ROW) {
continue;
}
std::string x_dir_name =
get_attribute(xml_direct, "x_dir", loc_data).as_string();
std::string y_dir_name =

View File

@ -89,14 +89,6 @@ static void read_xml_tile_global_port_annotation(
get_attribute(xml_tile, "is_clock", loc_data, pugiutil::ReqOpt::OPTIONAL)
.as_bool(false));
/* Get clock tree attributes if this is a clock */
if (tile_annotation.global_port_is_clock(tile_global_port_id)) {
tile_annotation.set_global_port_clock_arch_tree_name(
tile_global_port_id, get_attribute(xml_tile, "clock_arch_tree_name",
loc_data, pugiutil::ReqOpt::OPTIONAL)
.as_string());
}
/* Get is_set attributes */
tile_annotation.set_global_port_is_set(
tile_global_port_id,
@ -109,6 +101,16 @@ static void read_xml_tile_global_port_annotation(
get_attribute(xml_tile, "is_reset", loc_data, pugiutil::ReqOpt::OPTIONAL)
.as_bool(false));
/* Get clock tree attributes if this is a clock, reset or set */
if (tile_annotation.global_port_is_clock(tile_global_port_id) ||
tile_annotation.global_port_is_reset(tile_global_port_id) ||
tile_annotation.global_port_is_set(tile_global_port_id)) {
tile_annotation.set_global_port_clock_arch_tree_name(
tile_global_port_id, get_attribute(xml_tile, "clock_arch_tree_name",
loc_data, pugiutil::ReqOpt::OPTIONAL)
.as_string());
}
/* Get default_value attributes */
tile_annotation.set_global_port_default_value(
tile_global_port_id,

View File

@ -96,6 +96,11 @@ size_t TileAnnotation::global_port_default_value(
return global_port_default_values_[global_port_id];
}
bool TileAnnotation::global_port_thru_dedicated_network(
const TileGlobalPortId& global_port_id) const {
return !global_port_clock_arch_tree_name(global_port_id).empty();
}
std::string TileAnnotation::global_port_clock_arch_tree_name(
const TileGlobalPortId& global_port_id) const {
VTR_ASSERT(valid_global_port_id(global_port_id));

View File

@ -54,6 +54,8 @@ class TileAnnotation {
bool global_port_is_clock(const TileGlobalPortId& global_port_id) const;
bool global_port_is_set(const TileGlobalPortId& global_port_id) const;
bool global_port_is_reset(const TileGlobalPortId& global_port_id) const;
bool global_port_thru_dedicated_network(
const TileGlobalPortId& global_port_id) const;
std::string global_port_clock_arch_tree_name(
const TileGlobalPortId& global_port_id) const;
size_t global_port_default_value(

View File

@ -593,6 +593,15 @@ static void write_xml_circuit_model(std::fstream& fp, const char* fname,
circuit_lib.model_name(circuit_lib.pass_gate_logic_model(model)).c_str());
fp << "/>"
<< "\n";
fp << "\t\t\t"
<< "<last_stage_pass_gate_logic";
write_xml_attribute(
fp, "circuit_model_name",
circuit_lib
.model_name(circuit_lib.last_stage_pass_gate_logic_model(model))
.c_str());
fp << "/>"
<< "\n";
}
/* Write the ports of circuit model */

View File

@ -57,7 +57,7 @@ static void write_xml_direct_component_circuit(
fp, "circuit_model_name",
circuit_lib.model_name(arch_direct.circuit_model(direct_id)).c_str());
write_xml_attribute(fp, "type",
DIRECT_TYPE_STRING[arch_direct.type(direct_id)]);
DIRECT_TYPE_STRING[size_t(arch_direct.type(direct_id))]);
write_xml_attribute(fp, "x_dir",
DIRECT_DIRECTION_STRING[arch_direct.x_dir(direct_id)]);
write_xml_attribute(fp, "y_dir",

View File

@ -1,5 +1,5 @@
<clock_networks default_segment="seg_len1" default_switch="fast_switch">
<clock_network name="example_network" width="8">
<clock_networks default_segment="seg_len1" default_tap_switch="fast_switch" default_driver_switch="slow_switch">
<clock_network name="example_network" global_port="clk[0:7]">
<spine name="spine_lvl3" start_x="0" start_y="2" end_x="2" end_y="2">
<switch_point tap="spine_lvl2_upper" x="2" y="2"/>
<switch_point tap="spine_lvl2_lower" x="2" y="2"/>
@ -17,10 +17,10 @@
<spine name="rib_lvl1_lower_left" start_x="2" start_y="1" end_x="1" end_y="1"/>
<spine name="rib_lvl1_lower_right" start_x="2" start_y="1" end_x="3" end_y="1"/>
<taps>
<tap tile_pin="io[0:23].clk[0:7]"/>
<tap tile_pin="clb[0:0].clk[0:7]"/>
<tap tile_pin="dsp[0:0].clk[0:7]"/>
<tap tile_pin="bram[0:0].clk[0:7]"/>
<all from_pin="clk[0:0]" to_pin="io[0:23].clk[0:7]"/>
<all from_pin="clk[0:0]" to_pin="clb[0:0].clk[0:7]"/>
<all from_pin="clk[0:0]" to_pin="dsp[0:0].clk[0:7]"/>
<all from_pin="clk[0:0]" to_pin="bram[0:0].clk[0:7]"/>
</taps>
</clock_network>
</clock_networks>

View File

@ -0,0 +1,36 @@
<clock_networks default_segment="seg_len1" default_tap_switch="fast_switch" default_driver_switch="slow_switch">
<clock_network name="example_network" global_port="clk[0:7]">
<spine name="spine_lvl3" start_x="0" start_y="2" end_x="2" end_y="2">
<intermediate_driver x="1" y="2">
<tap from_pin="clb.O[0:0]" to_pin="clk[0:0]"/>
<tap from_pin="clb.O[1:1]" to_pin="clk[1:1]"/>
<tap from_pin="clb.O[2:3]" to_pin="clk[2:2]"/>
</intermediate_driver>
<switch_point tap="spine_lvl2_upper" x="2" y="2">
<internal_driver from_pin="clb.O[0:3]" to_pin="clk[1:1]"/>
</switch_point>
<switch_point tap="spine_lvl2_lower" x="2" y="2">
<internal_driver from_pin="clb.O[0:3]" to_pin="clk[0:0]"/>
</switch_point>
</spine>
<spine name="spine_lvl2_upper" start_x="2" start_y="2" end_x="2" end_y="3">
<switch_point tap="rib_lvl1_upper_left" x="2" y="3"/>
<switch_point tap="rib_lvl1_upper_right" x="2" y="3"/>
</spine>
<spine name="spine_lvl2_lower" start_x="2" start_y="2" end_x="2" end_y="1">
<switch_point tap="rib_lvl1_lower_left" x="2" y="1"/>
<switch_point tap="rib_lvl1_lower_right" x="2" y="1"/>
</spine>
<spine name="rib_lvl1_upper_left" start_x="2" start_y="3" end_x="1" end_y="3"/>
<spine name="rib_lvl1_upper_right" start_x="2" start_y="3" end_x="3" end_y="3"/>
<spine name="rib_lvl1_lower_left" start_x="2" start_y="1" end_x="1" end_y="1"/>
<spine name="rib_lvl1_lower_right" start_x="2" start_y="1" end_x="3" end_y="1"/>
<taps>
<all from_pin="clk[0:0]" to_pin="io[0:23].clk[0:0]"/>
<all from_pin="clk[0:0]" to_pin="clb[0:0].clk[1:1]"/>
<all from_pin="clk[0:0]" to_pin="dsp[0:0].clk[2:2]"/>
<single from_pin="clk[0:0]" to_pin="bram[0:0].clk[3:7]" x="1" y="1"/>
<region from_pin="clk[0:0]" to_pin="bram[0:0].clk[3:7]" start_x="1" end_x="10" repeat_x="2" start_y="8" end_y="20" repeat_y="8"/>
</taps>
</clock_network>
</clock_networks>

View File

@ -18,7 +18,10 @@ namespace openfpga { // Begin namespace openfpga
***********************************************************************/
ClockNetwork::ClockNetwork() {
default_segment_id_ = RRSegmentId::INVALID();
default_switch_id_ = RRSwitchId::INVALID();
default_tap_switch_id_ = RRSwitchId::INVALID();
default_driver_switch_id_ = RRSwitchId::INVALID();
/* Set a default invalid bounding box */
empty_tap_bb_ = vtr::Rect<size_t>(1, 0, 1, 0);
is_dirty_ = true;
}
@ -31,6 +34,12 @@ ClockNetwork::clock_tree_range ClockNetwork::trees() const {
return vtr::make_range(tree_ids_.begin(), tree_ids_.end());
}
ClockNetwork::clock_internal_driver_range ClockNetwork::internal_drivers()
const {
return vtr::make_range(internal_driver_ids_.begin(),
internal_driver_ids_.end());
}
std::vector<ClockLevelId> ClockNetwork::levels(
const ClockTreeId& tree_id) const {
std::vector<ClockLevelId> ret;
@ -172,11 +181,20 @@ RRSegmentId ClockNetwork::default_segment() const {
return default_segment_id_;
}
std::string ClockNetwork::default_switch_name() const {
return default_switch_name_;
std::string ClockNetwork::default_tap_switch_name() const {
return default_tap_switch_name_;
}
RRSwitchId ClockNetwork::default_switch() const { return default_switch_id_; }
std::string ClockNetwork::default_driver_switch_name() const {
return default_driver_switch_name_;
}
RRSwitchId ClockNetwork::default_tap_switch() const {
return default_tap_switch_id_;
}
RRSwitchId ClockNetwork::default_driver_switch() const {
return default_driver_switch_id_;
}
std::string ClockNetwork::tree_name(const ClockTreeId& tree_id) const {
VTR_ASSERT(valid_tree_id(tree_id));
@ -199,9 +217,14 @@ size_t ClockNetwork::max_tree_depth() const {
return max_size;
}
BasicPort ClockNetwork::tree_global_port(const ClockTreeId& tree_id) const {
VTR_ASSERT(valid_tree_id(tree_id));
return tree_global_ports_[tree_id];
}
size_t ClockNetwork::tree_width(const ClockTreeId& tree_id) const {
VTR_ASSERT(valid_tree_id(tree_id));
return tree_widths_[tree_id];
return tree_global_ports_[tree_id].get_width();
}
size_t ClockNetwork::tree_depth(const ClockTreeId& tree_id) const {
@ -247,6 +270,54 @@ vtr::Point<int> ClockNetwork::spine_end_point(
return spine_end_points_[spine_id];
}
std::vector<ClockInternalDriverId> ClockNetwork::spine_intermediate_drivers(
const ClockSpineId& spine_id, const vtr::Point<int>& coord) const {
VTR_ASSERT(valid_spine_id(spine_id));
/* Convert coord to a unique string */
std::string coord_str =
std::to_string(coord.x()) + std::string(",") + std::to_string(coord.y());
auto result = spine_intermediate_drivers_[spine_id].find(coord_str);
if (result == spine_intermediate_drivers_[spine_id].end()) {
return std::vector<ClockInternalDriverId>();
}
return result->second;
}
vtr::Point<int> ClockNetwork::spine_intermediate_driver_routing_track_coord(
const ClockSpineId& spine_id, const vtr::Point<int>& coord) const {
vtr::Point<int> des_coord(coord.x(), coord.y());
Direction des_spine_direction = spine_direction(spine_id);
/* des node depends on the type of routing track and direction. But it
* should be a starting point at the current SB[x][y] */
if (des_spine_direction == Direction::INC &&
spine_track_type(spine_id) == CHANX) {
des_coord.set_x(coord.x() + 1);
}
if (des_spine_direction == Direction::INC &&
spine_track_type(spine_id) == CHANY) {
des_coord.set_y(coord.y() + 1);
}
return des_coord;
}
std::vector<ClockInternalDriverId>
ClockNetwork::spine_intermediate_drivers_by_routing_track(
const ClockSpineId& spine_id, const vtr::Point<int>& track_coord) const {
vtr::Point<int> des_coord(track_coord.x(), track_coord.y());
Direction des_spine_direction = spine_direction(spine_id);
/* des node depends on the type of routing track and direction. But it
* should be a starting point at the current SB[x][y] */
if (des_spine_direction == Direction::INC &&
spine_track_type(spine_id) == CHANX) {
des_coord.set_x(track_coord.x() - 1);
}
if (des_spine_direction == Direction::INC &&
spine_track_type(spine_id) == CHANY) {
des_coord.set_y(track_coord.y() - 1);
}
return spine_intermediate_drivers(spine_id, des_coord);
}
ClockLevelId ClockNetwork::spine_level(const ClockSpineId& spine_id) const {
VTR_ASSERT(valid_spine_id(spine_id));
if (is_dirty_) {
@ -315,17 +386,163 @@ vtr::Point<int> ClockNetwork::spine_switch_point(
return spine_switch_coords_[spine_id][size_t(switch_point_id)];
}
std::vector<std::string> ClockNetwork::tree_taps(
std::vector<ClockSwitchPointId>
ClockNetwork::find_spine_switch_points_with_coord(
const ClockSpineId& spine_id, const vtr::Point<int>& coord) const {
VTR_ASSERT(valid_spine_id(spine_id));
std::vector<ClockSwitchPointId> ret;
for (size_t i = 0; i < spine_switch_points_[spine_id].size(); ++i) {
if (spine_switch_coords_[spine_id][i] == coord) {
ret.push_back(ClockSwitchPointId(i));
}
}
return ret;
}
std::vector<ClockInternalDriverId>
ClockNetwork::spine_switch_point_internal_drivers(
const ClockSpineId& spine_id,
const ClockSwitchPointId& switch_point_id) const {
VTR_ASSERT(valid_spine_switch_point_id(spine_id, switch_point_id));
return spine_switch_internal_drivers_[spine_id][size_t(switch_point_id)];
}
std::string ClockNetwork::internal_driver_from_pin(
const ClockInternalDriverId& int_driver_id) const {
VTR_ASSERT(valid_internal_driver_id(int_driver_id));
return internal_driver_from_pins_[int_driver_id];
}
BasicPort ClockNetwork::internal_driver_to_pin(
const ClockInternalDriverId& int_driver_id) const {
VTR_ASSERT(valid_internal_driver_id(int_driver_id));
return internal_driver_to_pins_[int_driver_id];
}
std::vector<ClockTapId> ClockNetwork::tree_taps(
const ClockTreeId& tree_id) const {
VTR_ASSERT(valid_tree_id(tree_id));
return tree_taps_[tree_id];
}
std::vector<std::string> ClockNetwork::tree_flatten_taps(
const ClockTreeId& tree_id, const ClockTreePinId& clk_pin_id) const {
BasicPort ClockNetwork::tap_from_port(const ClockTapId& tap_id) const {
VTR_ASSERT(valid_tap_id(tap_id));
return tap_from_ports_[tap_id];
}
std::string ClockNetwork::tap_to_port(const ClockTapId& tap_id) const {
VTR_ASSERT(valid_tap_id(tap_id));
return tap_to_ports_[tap_id];
}
ClockNetwork::e_tap_type ClockNetwork::tap_type(
const ClockTapId& tap_id) const {
VTR_ASSERT(valid_tap_id(tap_id));
/* If not a region, it is a default type covering all the coordinates*/
if (tap_bbs_[tap_id] == empty_tap_bb_) {
return ClockNetwork::e_tap_type::ALL;
}
/* Now check if this a single point */
if (tap_bbs_[tap_id].height() == 0 && tap_bbs_[tap_id].width() == 0) {
return ClockNetwork::e_tap_type::SINGLE;
}
return ClockNetwork::e_tap_type::REGION;
}
size_t ClockNetwork::tap_x(const ClockTapId& tap_id) const {
VTR_ASSERT(tap_type(tap_id) == ClockNetwork::e_tap_type::SINGLE);
return tap_bbs_[tap_id].xmin();
}
size_t ClockNetwork::tap_y(const ClockTapId& tap_id) const {
VTR_ASSERT(tap_type(tap_id) == ClockNetwork::e_tap_type::SINGLE);
return tap_bbs_[tap_id].ymin();
}
vtr::Rect<size_t> ClockNetwork::tap_bounding_box(
const ClockTapId& tap_id) const {
VTR_ASSERT(tap_type(tap_id) == ClockNetwork::e_tap_type::REGION);
return tap_bbs_[tap_id];
}
size_t ClockNetwork::tap_step_x(const ClockTapId& tap_id) const {
VTR_ASSERT(tap_type(tap_id) == ClockNetwork::e_tap_type::REGION);
return tap_bb_steps_[tap_id].x();
}
size_t ClockNetwork::tap_step_y(const ClockTapId& tap_id) const {
VTR_ASSERT(tap_type(tap_id) == ClockNetwork::e_tap_type::REGION);
return tap_bb_steps_[tap_id].y();
}
bool ClockNetwork::valid_tap_coord_in_bb(
const ClockTapId& tap_id, const vtr::Point<size_t>& tap_coord) const {
VTR_ASSERT(valid_tap_id(tap_id));
if (tap_type(tap_id) == ClockNetwork::e_tap_type::ALL) {
return true;
}
if (tap_type(tap_id) == ClockNetwork::e_tap_type::SINGLE &&
tap_bbs_[tap_id].coincident(tap_coord)) {
return true;
}
if (tap_type(tap_id) == ClockNetwork::e_tap_type::REGION &&
tap_bbs_[tap_id].coincident(tap_coord)) {
/* Check if steps are considered, coords still matches */
bool x_in_bb = false;
for (size_t ix = tap_bbs_[tap_id].xmin(); ix <= tap_bbs_[tap_id].xmax();
ix = ix + tap_bb_steps_[tap_id].x()) {
if (tap_coord.x() == ix) {
x_in_bb = true;
break;
}
}
/* Early exit */
if (!x_in_bb) {
return false;
}
bool y_in_bb = false;
for (size_t iy = tap_bbs_[tap_id].ymin(); iy <= tap_bbs_[tap_id].ymax();
iy = iy + tap_bb_steps_[tap_id].y()) {
if (tap_coord.y() == iy) {
y_in_bb = true;
break;
}
}
if (y_in_bb && x_in_bb) {
return true;
}
}
return false;
}
std::vector<std::string> ClockNetwork::tree_flatten_tap_to_ports(
const ClockTreeId& tree_id, const ClockTreePinId& clk_pin_id,
const vtr::Point<size_t>& tap_coord) const {
VTR_ASSERT(valid_tree_id(tree_id));
std::vector<std::string> flatten_taps;
for (const std::string& tap_name : tree_taps_[tree_id]) {
for (ClockTapId tap_id : tree_taps_[tree_id]) {
VTR_ASSERT(valid_tap_id(tap_id));
/* Filter out unmatched from ports. Expect [clk_pin_id:clk_pin_id] */
BasicPort from_port = tap_from_ports_[tap_id];
if (!from_port.is_valid()) {
VTR_LOG_ERROR("Invalid from port name '%s' whose index is not valid\n",
from_port.to_verilog_string().c_str());
exit(1);
}
if (from_port.get_width() != 1) {
VTR_LOG_ERROR("Invalid from port name '%s' whose width is not 1\n",
from_port.to_verilog_string().c_str());
exit(1);
}
if (from_port.get_lsb() != size_t(clk_pin_id)) {
continue;
}
/* Filter out unmatched coordinates */
if (!valid_tap_coord_in_bb(tap_id, tap_coord)) {
continue;
}
std::string tap_name = tap_to_ports_[tap_id];
StringToken tokenizer(tap_name);
std::vector<std::string> pin_tokens = tokenizer.split(".");
if (pin_tokens.size() != 2) {
@ -351,9 +568,6 @@ std::vector<std::string> ClockNetwork::tree_flatten_taps(
std::string flatten_tile_str =
tile_info.get_name() + "[" + std::to_string(tile_idx) + "]";
for (size_t& pin_idx : pin_info.pins()) {
if (pin_idx != size_t(clk_pin_id)) {
continue;
}
std::string flatten_pin_str =
pin_info.get_name() + "[" + std::to_string(pin_idx) + "]";
flatten_taps.push_back(flatten_tile_str + "." + flatten_pin_str);
@ -363,6 +577,63 @@ std::vector<std::string> ClockNetwork::tree_flatten_taps(
return flatten_taps;
}
std::vector<std::string> ClockNetwork::flatten_internal_driver_from_pin(
const ClockInternalDriverId& int_driver_id,
const ClockTreePinId& clk_pin_id) const {
std::vector<std::string> flatten_taps;
BasicPort des_pin = internal_driver_to_pin(int_driver_id);
if (!des_pin.is_valid()) {
VTR_LOG_ERROR(
"Invalid internal driver destination port name '%s' whose index is not "
"valid\n",
des_pin.to_verilog_string().c_str());
exit(1);
}
if (des_pin.get_width() != 1) {
VTR_LOG_ERROR(
"Invalid internal driver destination port name '%s' whose width is not "
"1\n",
des_pin.to_verilog_string().c_str());
exit(1);
}
if (des_pin.get_lsb() != size_t(clk_pin_id)) {
return flatten_taps;
}
std::string tap_name = internal_driver_from_pin(int_driver_id);
StringToken tokenizer(tap_name);
std::vector<std::string> pin_tokens = tokenizer.split(".");
if (pin_tokens.size() != 2) {
VTR_LOG_ERROR("Invalid pin name '%s'. Expect <tile>.<port>\n",
tap_name.c_str());
exit(1);
}
PortParser tile_parser(pin_tokens[0]);
BasicPort tile_info = tile_parser.port();
PortParser pin_parser(pin_tokens[1]);
BasicPort pin_info = pin_parser.port();
if (!tile_info.is_valid()) {
VTR_LOG_ERROR("Invalid pin name '%s' whose subtile index is not valid\n",
tap_name.c_str());
exit(1);
}
if (!pin_info.is_valid()) {
VTR_LOG_ERROR("Invalid pin name '%s' whose pin index is not valid\n",
tap_name.c_str());
exit(1);
}
for (size_t& tile_idx : tile_info.pins()) {
std::string flatten_tile_str =
tile_info.get_name() + "[" + std::to_string(tile_idx) + "]";
for (size_t& pin_idx : pin_info.pins()) {
std::string flatten_pin_str =
pin_info.get_name() + "[" + std::to_string(pin_idx) + "]";
flatten_taps.push_back(flatten_tile_str + "." + flatten_pin_str);
}
}
return flatten_taps;
}
ClockTreeId ClockNetwork::find_tree(const std::string& name) const {
auto result = tree_name2id_map_.find(name);
if (result == tree_name2id_map_.end()) {
@ -400,6 +671,8 @@ void ClockNetwork::reserve_spines(const size_t& num_spines) {
spine_track_types_.reserve(num_spines);
spine_switch_points_.reserve(num_spines);
spine_switch_coords_.reserve(num_spines);
spine_switch_internal_drivers_.reserve(num_spines);
spine_intermediate_drivers_.reserve(num_spines);
spine_parents_.reserve(num_spines);
spine_children_.reserve(num_spines);
spine_parent_trees_.reserve(num_spines);
@ -408,7 +681,7 @@ void ClockNetwork::reserve_spines(const size_t& num_spines) {
void ClockNetwork::reserve_trees(const size_t& num_trees) {
tree_ids_.reserve(num_trees);
tree_names_.reserve(num_trees);
tree_widths_.reserve(num_trees);
tree_global_ports_.reserve(num_trees);
tree_top_spines_.reserve(num_trees);
tree_taps_.reserve(num_trees);
}
@ -417,25 +690,40 @@ void ClockNetwork::set_default_segment(const RRSegmentId& seg_id) {
default_segment_id_ = seg_id;
}
void ClockNetwork::set_default_switch(const RRSwitchId& switch_id) {
default_switch_id_ = switch_id;
void ClockNetwork::set_default_tap_switch(const RRSwitchId& switch_id) {
default_tap_switch_id_ = switch_id;
}
void ClockNetwork::set_default_driver_switch(const RRSwitchId& switch_id) {
default_driver_switch_id_ = switch_id;
}
void ClockNetwork::set_default_segment_name(const std::string& name) {
default_segment_name_ = name;
}
void ClockNetwork::set_default_switch_name(const std::string& name) {
default_switch_name_ = name;
void ClockNetwork::set_default_tap_switch_name(const std::string& name) {
default_tap_switch_name_ = name;
}
ClockTreeId ClockNetwork::create_tree(const std::string& name, size_t width) {
void ClockNetwork::set_default_driver_switch_name(const std::string& name) {
default_driver_switch_name_ = name;
}
ClockTreeId ClockNetwork::create_tree(const std::string& name,
const BasicPort& global_port) {
/* Sanity checks */
if (!global_port.is_valid()) {
VTR_LOG_ERROR("Invalid global port '%s' for clock tree name '%s'\n",
global_port.to_verilog_string().c_str(), name.c_str());
exit(1);
}
/* Create a new id */
ClockTreeId tree_id = ClockTreeId(tree_ids_.size());
tree_ids_.push_back(tree_id);
tree_names_.push_back(name);
tree_widths_.push_back(width);
tree_global_ports_.push_back(global_port);
tree_depths_.emplace_back();
tree_taps_.emplace_back();
tree_top_spines_.emplace_back();
@ -476,6 +764,8 @@ ClockSpineId ClockNetwork::create_spine(const std::string& name) {
spine_track_types_.emplace_back(NUM_RR_TYPES);
spine_switch_points_.emplace_back();
spine_switch_coords_.emplace_back();
spine_switch_internal_drivers_.emplace_back();
spine_intermediate_drivers_.emplace_back();
spine_parents_.emplace_back();
spine_children_.emplace_back();
spine_parent_trees_.emplace_back();
@ -526,13 +816,14 @@ void ClockNetwork::set_spine_track_type(const ClockSpineId& spine_id,
spine_track_types_[spine_id] = type;
}
void ClockNetwork::add_spine_switch_point(const ClockSpineId& spine_id,
const ClockSpineId& drive_spine_id,
const vtr::Point<int>& coord) {
ClockSwitchPointId ClockNetwork::add_spine_switch_point(
const ClockSpineId& spine_id, const ClockSpineId& drive_spine_id,
const vtr::Point<int>& coord) {
VTR_ASSERT(valid_spine_id(spine_id));
VTR_ASSERT(valid_spine_id(drive_spine_id));
spine_switch_points_[spine_id].push_back(drive_spine_id);
spine_switch_coords_[spine_id].push_back(coord);
spine_switch_internal_drivers_[spine_id].emplace_back();
/* Do not allow any spine has different parents */
if (spine_parents_[drive_spine_id]) {
VTR_LOG_ERROR(
@ -545,12 +836,143 @@ void ClockNetwork::add_spine_switch_point(const ClockSpineId& spine_id,
}
spine_parents_[drive_spine_id] = spine_id;
spine_children_[spine_id].push_back(drive_spine_id);
return ClockSwitchPointId(spine_switch_points_[spine_id].size() - 1);
}
void ClockNetwork::add_tree_tap(const ClockTreeId& tree_id,
const std::string& pin_name) {
ClockInternalDriverId ClockNetwork::add_spine_switch_point_internal_driver(
const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id,
const std::string& int_driver_from_port,
const std::string& int_driver_to_port) {
VTR_ASSERT(valid_spine_id(spine_id));
VTR_ASSERT(valid_spine_switch_point_id(spine_id, switch_point_id));
/* Parse ports */
PortParser to_pin_parser(int_driver_to_port);
/* Find any existing id for the driver port */
for (ClockInternalDriverId int_driver_id : internal_driver_ids_) {
if (internal_driver_from_pins_[int_driver_id] == int_driver_from_port &&
internal_driver_to_pins_[int_driver_id] == to_pin_parser.port()) {
spine_switch_internal_drivers_[spine_id][size_t(switch_point_id)]
.push_back(int_driver_id);
return int_driver_id;
}
}
/* Reaching here, no existing id can be reused, create a new one */
ClockInternalDriverId int_driver_id =
ClockInternalDriverId(internal_driver_ids_.size());
internal_driver_ids_.push_back(int_driver_id);
internal_driver_from_pins_.push_back(int_driver_from_port);
internal_driver_to_pins_.push_back(to_pin_parser.port());
spine_switch_internal_drivers_[spine_id][size_t(switch_point_id)].push_back(
int_driver_id);
return int_driver_id;
}
ClockInternalDriverId ClockNetwork::add_spine_intermediate_driver(
const ClockSpineId& spine_id, const vtr::Point<int>& coord,
const std::string& int_driver_from_port,
const std::string& int_driver_to_port) {
VTR_ASSERT(valid_spine_id(spine_id));
/* Convert coord to a unique string */
std::string coord_str =
std::to_string(coord.x()) + std::string(",") + std::to_string(coord.y());
/* Parse ports */
PortParser to_pin_parser(int_driver_to_port);
/* Find any existing id for the driver port */
ClockInternalDriverId int_driver_id_to_add =
ClockInternalDriverId(internal_driver_ids_.size());
for (ClockInternalDriverId int_driver_id : internal_driver_ids_) {
if (internal_driver_from_pins_[int_driver_id] == int_driver_from_port &&
internal_driver_to_pins_[int_driver_id] == to_pin_parser.port()) {
int_driver_id_to_add = int_driver_id;
break;
}
}
/* Reaching here, no existing id can be reused, create a new one */
if (int_driver_id_to_add ==
ClockInternalDriverId(internal_driver_ids_.size())) {
internal_driver_ids_.push_back(int_driver_id_to_add);
internal_driver_from_pins_.push_back(int_driver_from_port);
internal_driver_to_pins_.push_back(to_pin_parser.port());
}
/* Add it to existing map, avoid duplicated id */
auto result = spine_intermediate_drivers_[spine_id].find(coord_str);
if (result == spine_intermediate_drivers_[spine_id].end()) {
spine_intermediate_drivers_[spine_id][coord_str].push_back(
int_driver_id_to_add);
} else {
if (std::find(result->second.begin(), result->second.end(),
int_driver_id_to_add) == result->second.end()) {
result->second.push_back(int_driver_id_to_add);
} else {
VTR_LOG_WARN(
"Skip intermediate driver (from_port='%s', to_port='%s') at (%s) as it "
"is duplicated in the clock architecture description file!\n",
int_driver_from_port.c_str(), int_driver_to_port.c_str(),
coord_str.c_str());
}
}
return int_driver_id_to_add;
}
ClockTapId ClockNetwork::add_tree_tap(const ClockTreeId& tree_id,
const BasicPort& from_port,
const std::string& to_port) {
VTR_ASSERT(valid_tree_id(tree_id));
tree_taps_[tree_id].push_back(pin_name);
/* TODO: Consider find existing tap template and avoid duplication in storage
*/
ClockTapId tap_id = ClockTapId(tap_ids_.size());
tap_ids_.push_back(tap_id);
tap_from_ports_.push_back(from_port);
tap_to_ports_.push_back(to_port);
tap_bbs_.emplace_back(empty_tap_bb_);
tap_bb_steps_.emplace_back(vtr::Point<size_t>(0, 0));
tree_taps_[tree_id].push_back(tap_id);
return tap_id;
}
bool ClockNetwork::set_tap_bounding_box(const ClockTapId& tap_id,
const vtr::Rect<size_t>& bb) {
VTR_ASSERT(valid_tap_id(tap_id));
/* Check the bounding box, ensure it must be valid */
if (bb.xmax() < bb.xmin() || bb.ymax() < bb.ymin()) {
VTR_LOG_ERROR(
"Invalid bounding box (xlow=%lu, ylow=%lu) -> (xhigh=%lu, yhigh=%lu)! "
"Must follow: xlow <= xhigh, ylow <= yhigh!\n",
bb.xmin(), bb.ymin(), bb.xmax(), bb.ymax());
return false;
}
tap_bbs_[tap_id] = bb;
return true;
}
bool ClockNetwork::set_tap_step_x(const ClockTapId& tap_id,
const size_t& step) {
VTR_ASSERT(valid_tap_id(tap_id));
/* Must be a valid step >= 1 */
if (step == 0) {
VTR_LOG_ERROR(
"Invalid x-direction step (=%lu) for any bounding box! Expect an integer "
">= 1!\n",
step);
return false;
}
tap_bb_steps_[tap_id].set_x(step);
return true;
}
bool ClockNetwork::set_tap_step_y(const ClockTapId& tap_id,
const size_t& step) {
VTR_ASSERT(valid_tap_id(tap_id));
/* Must be a valid step >= 1 */
if (step == 0) {
VTR_LOG_ERROR(
"Invalid y-direction step (=%lu) for any bounding box! Expect an integer "
">= 1!\n",
step);
return false;
}
tap_bb_steps_[tap_id].set_y(step);
return true;
}
bool ClockNetwork::link() {
@ -562,6 +984,25 @@ bool ClockNetwork::link() {
return true;
}
bool ClockNetwork::validate_tree_taps() const {
for (ClockTreeId tree_id : trees()) {
for (ClockTapId tap_id : tree_taps(tree_id)) {
/* The from pin name should match the global port */
if (!tree_global_port(tree_id).mergeable(tap_from_port(tap_id)) ||
!tree_global_port(tree_id).contained(tap_from_port(tap_id))) {
VTR_LOG_ERROR(
"Tap point from_port '%s' is not part of the global port '%s' of "
"tree '%s'\n",
tap_from_port(tap_id).to_verilog_string().c_str(),
tree_global_port(tree_id).to_verilog_string().c_str(),
tree_name(tree_id).c_str());
return false;
}
}
}
return true;
}
bool ClockNetwork::validate_tree() const {
for (ClockTreeId tree_id : trees()) {
for (ClockSpineId spine_id : spines(tree_id)) {
@ -622,7 +1063,8 @@ bool ClockNetwork::validate_tree() const {
bool ClockNetwork::validate() const {
is_dirty_ = true;
if (default_segment_id_ && default_switch_id_ && validate_tree()) {
if (default_segment_id_ && default_tap_switch_id_ &&
default_driver_switch_id_ && validate_tree() && validate_tree_taps()) {
is_dirty_ = false;
}
return true;
@ -698,6 +1140,16 @@ bool ClockNetwork::valid_tree_id(const ClockTreeId& tree_id) const {
(tree_id == tree_ids_[tree_id]);
}
bool ClockNetwork::valid_internal_driver_id(
const ClockInternalDriverId& int_driver_id) const {
return (size_t(int_driver_id) < internal_driver_ids_.size()) &&
(int_driver_id == internal_driver_ids_[int_driver_id]);
}
bool ClockNetwork::valid_tap_id(const ClockTapId& tap_id) const {
return (size_t(tap_id) < tap_ids_.size()) && (tap_id == tap_ids_[tap_id]);
}
bool ClockNetwork::valid_level_id(const ClockTreeId& tree_id,
const ClockLevelId& lvl_id) const {
return valid_tree_id(tree_id) && (size_t(lvl_id) < tree_depth(tree_id));

View File

@ -14,6 +14,7 @@
/* Headers from openfpgautil library */
#include "clock_network_fwd.h"
#include "openfpga_port.h"
#include "rr_graph_fwd.h"
#include "rr_node_types.h"
@ -42,6 +43,14 @@ class ClockNetwork {
clock_tree_iterator;
/* Create range */
typedef vtr::Range<clock_tree_iterator> clock_tree_range;
typedef vtr::vector<ClockInternalDriverId,
ClockInternalDriverId>::const_iterator
clock_internal_driver_iterator;
/* Create range */
typedef vtr::Range<clock_internal_driver_iterator>
clock_internal_driver_range;
/* Type of tap points */
enum class e_tap_type : unsigned char { ALL = 0, SINGLE, REGION, NUM_TYPES };
public: /* Constructors */
ClockNetwork();
@ -49,6 +58,7 @@ class ClockNetwork {
public: /* Accessors: aggregates */
size_t num_trees() const;
clock_tree_range trees() const;
clock_internal_driver_range internal_drivers() const;
/* Return the range of clock levels */
std::vector<ClockLevelId> levels(const ClockTreeId& tree_id) const;
/* Return a list of spine id under a clock tree */
@ -73,9 +83,12 @@ class ClockNetwork {
* information from RRGraph */
RRSegmentId default_segment() const;
std::string default_segment_name() const;
RRSwitchId default_switch() const;
std::string default_switch_name() const;
RRSwitchId default_tap_switch() const;
std::string default_tap_switch_name() const;
RRSwitchId default_driver_switch() const;
std::string default_driver_switch_name() const;
std::string tree_name(const ClockTreeId& tree_id) const;
BasicPort tree_global_port(const ClockTreeId& tree_id) const;
size_t tree_width(const ClockTreeId& tree_id) const;
size_t tree_depth(const ClockTreeId& tree_id) const;
size_t max_tree_width() const;
@ -84,6 +97,27 @@ class ClockNetwork {
std::string spine_name(const ClockSpineId& spine_id) const;
vtr::Point<int> spine_start_point(const ClockSpineId& spine_id) const;
vtr::Point<int> spine_end_point(const ClockSpineId& spine_id) const;
/* Find the intermediate drivers by the SB coordinate */
std::vector<ClockInternalDriverId> spine_intermediate_drivers(
const ClockSpineId& spine_id, const vtr::Point<int>& coord) const;
/* Find the coordinate of routing track which the intermediate driver will
* driver. Note that the coordinate may be different than the coordinate of
* intermeidate driver. One of the exceptions lies in the CHANX with INC
* direction, which starts actually on the routing tracks on the right side of
* a SB, resulting in x -> x + 1. Another exception is on the CHANY with INC
* direction, which starts actually on the routing tracks on the top side of a
* SB, resulting in y - > y + 1. This function is to provide an official
* conversion the coordinates. */
vtr::Point<int> spine_intermediate_driver_routing_track_coord(
const ClockSpineId& spine_id, const vtr::Point<int>& coord) const;
/* Find the intermediate drivers by the routing track starting point. Note
* that the routing track starting point may be different from the SB
* coordinate. See the exceptions in the
* spine_intermediate_driver_track_coord() */
std::vector<ClockInternalDriverId>
spine_intermediate_drivers_by_routing_track(
const ClockSpineId& spine_id, const vtr::Point<int>& track_coord) const;
/* Return the level where the spine locates in the multi-layer clock tree
* structure */
ClockLevelId spine_level(const ClockSpineId& spine_id) const;
@ -114,15 +148,51 @@ class ClockNetwork {
vtr::Point<int> spine_switch_point(
const ClockSpineId& spine_id,
const ClockSwitchPointId& switch_point_id) const;
/* Find all the switching points at a given coordinate */
std::vector<ClockSwitchPointId> find_spine_switch_points_with_coord(
const ClockSpineId& spine_id, const vtr::Point<int>& coord) const;
std::vector<ClockInternalDriverId> spine_switch_point_internal_drivers(
const ClockSpineId& spine_id,
const ClockSwitchPointId& switch_point_id) const;
std::string internal_driver_from_pin(
const ClockInternalDriverId& int_driver_id) const;
std::vector<std::string> flatten_internal_driver_from_pin(
const ClockInternalDriverId& int_driver_id,
const ClockTreePinId& clk_pin_id) const;
BasicPort internal_driver_to_pin(
const ClockInternalDriverId& int_driver_id) const;
/* Return the original list of tap pins that is in storage; useful for parsers
*/
std::vector<std::string> tree_taps(const ClockTreeId& tree_id) const;
std::vector<ClockTapId> tree_taps(const ClockTreeId& tree_id) const;
/* Return the source ports for a given tap */
BasicPort tap_from_port(const ClockTapId& tap_id) const;
/* Return the destination ports for a given tap */
std::string tap_to_port(const ClockTapId& tap_id) const;
/* Find the type of tap point:
* all -> all coordinates in efpga are required to tap
* single -> only 1 coordinate is required to tap
* region -> coordinates in a region required to tap. Steps in region may be
* required
*/
e_tap_type tap_type(const ClockTapId& tap_id) const;
/* Require the type of single */
size_t tap_x(const ClockTapId& tap_id) const;
size_t tap_y(const ClockTapId& tap_id) const;
/* Require the type of region */
vtr::Rect<size_t> tap_bounding_box(const ClockTapId& tap_id) const;
/* Steps are only available when type is region */
size_t tap_step_x(const ClockTapId& tap_id) const;
size_t tap_step_y(const ClockTapId& tap_id) const;
/* Return the list of flatten tap pins. For example: clb[0:1].clk[2:2] is
* flatten to { clb[0].clk[2], clb[1].clk[2] } Useful to build clock routing
* resource graph Note that the clk_pin_id limits only 1 clock to be accessed
*/
std::vector<std::string> tree_flatten_taps(
const ClockTreeId& tree_id, const ClockTreePinId& clk_pin_id) const;
std::vector<std::string> tree_flatten_tap_to_ports(
const ClockTreeId& tree_id, const ClockTreePinId& clk_pin_id,
const vtr::Point<size_t>& tap_coord) const;
/* Find a spine with a given name, if not found, return an valid id, otherwise
* return an invalid one */
ClockSpineId find_spine(const std::string& name) const;
@ -145,12 +215,15 @@ class ClockNetwork {
/* Reserve a number of trees to be memory efficent */
void reserve_trees(const size_t& num_trees);
void set_default_segment(const RRSegmentId& seg_id);
void set_default_switch(const RRSwitchId& switch_id);
void set_default_tap_switch(const RRSwitchId& switch_id);
void set_default_driver_switch(const RRSwitchId& switch_id);
void set_default_segment_name(const std::string& name);
void set_default_switch_name(const std::string& name);
void set_default_tap_switch_name(const std::string& name);
void set_default_driver_switch_name(const std::string& name);
/* Create a new tree, by default the tree can accomodate only 1 clock signal;
* use width to adjust the size */
ClockTreeId create_tree(const std::string& name, size_t width = 1);
ClockTreeId create_tree(const std::string& name,
const BasicPort& global_port);
/* Create a new spine, if the spine is already created, return an invalid id
*/
ClockSpineId create_spine(const std::string& name);
@ -168,10 +241,24 @@ class ClockNetwork {
void set_spine_direction(const ClockSpineId& spine_id, const Direction& dir);
void set_spine_track_type(const ClockSpineId& spine_id,
const t_rr_type& type);
void add_spine_switch_point(const ClockSpineId& spine_id,
const ClockSpineId& drive_spine_id,
const vtr::Point<int>& coord);
void add_tree_tap(const ClockTreeId& tree_id, const std::string& pin_name);
ClockSwitchPointId add_spine_switch_point(const ClockSpineId& spine_id,
const ClockSpineId& drive_spine_id,
const vtr::Point<int>& coord);
ClockInternalDriverId add_spine_switch_point_internal_driver(
const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id,
const std::string& internal_driver_from_port,
const std::string& internal_driver_to_port);
ClockInternalDriverId add_spine_intermediate_driver(
const ClockSpineId& spine_id, const vtr::Point<int>& coord,
const std::string& internal_driver_from_port,
const std::string& internal_driver_to_port);
ClockTapId add_tree_tap(const ClockTreeId& tree_id,
const BasicPort& from_port,
const std::string& to_port);
bool set_tap_bounding_box(const ClockTapId& tap_id,
const vtr::Rect<size_t>& bb);
bool set_tap_step_x(const ClockTapId& tap_id, const size_t& step);
bool set_tap_step_y(const ClockTapId& tap_id, const size_t& step);
/* Build internal links between clock tree, spines etc. This is also an
* validator to verify the correctness of the clock network. Must run before
* using the data! */
@ -208,7 +295,16 @@ class ClockNetwork {
private: /* Public invalidators/validators */
/* Ensure tree data is clean. All the spines are valid, and switch points are
* valid */
bool validate_tree_taps() const;
bool validate_tree() const;
/* Show if the internal driver id is a valid for data queries */
bool valid_internal_driver_id(
const ClockInternalDriverId& int_driver_id) const;
/* Show if the tap id is a valid for data queries */
bool valid_tap_id(const ClockTapId& tap_id) const;
/* Check if a given coordinate matches the requirements for a tap point */
bool valid_tap_coord_in_bb(const ClockTapId& tap_id,
const vtr::Point<size_t>& tap_coord) const;
private: /* Private mutators */
/* Build internal links between spines under a given tree */
@ -226,10 +322,10 @@ class ClockNetwork {
/* Basic information of each tree */
vtr::vector<ClockTreeId, ClockTreeId> tree_ids_;
vtr::vector<ClockTreeId, std::string> tree_names_;
vtr::vector<ClockTreeId, size_t> tree_widths_;
vtr::vector<ClockTreeId, BasicPort> tree_global_ports_;
vtr::vector<ClockTreeId, size_t> tree_depths_;
vtr::vector<ClockTreeId, std::vector<ClockSpineId>> tree_top_spines_;
vtr::vector<ClockTreeId, std::vector<std::string>> tree_taps_;
vtr::vector<ClockTreeId, std::vector<ClockTapId>> tree_taps_;
/* Basic information of each spine */
vtr::vector<ClockSpineId, ClockSpineId> spine_ids_;
@ -241,22 +337,47 @@ class ClockNetwork {
vtr::vector<ClockSpineId, t_rr_type> spine_track_types_;
vtr::vector<ClockSpineId, std::vector<ClockSpineId>> spine_switch_points_;
vtr::vector<ClockSpineId, std::vector<vtr::Point<int>>> spine_switch_coords_;
vtr::vector<ClockSpineId, std::vector<std::vector<ClockInternalDriverId>>>
spine_switch_internal_drivers_;
vtr::vector<ClockSpineId,
std::map<std::string, std::vector<ClockInternalDriverId>>>
spine_intermediate_drivers_;
vtr::vector<ClockSpineId, ClockSpineId> spine_parents_;
vtr::vector<ClockSpineId, std::vector<ClockSpineId>> spine_children_;
vtr::vector<ClockSpineId, ClockTreeId> spine_parent_trees_;
/* Basic Information about internal drivers */
vtr::vector<ClockInternalDriverId, ClockInternalDriverId>
internal_driver_ids_;
vtr::vector<ClockInternalDriverId, std::string> internal_driver_from_pins_;
vtr::vector<ClockInternalDriverId, BasicPort> internal_driver_to_pins_;
/* Basic information about tap */
vtr::vector<ClockTapId, ClockTapId> tap_ids_;
vtr::vector<ClockTapId, BasicPort> tap_from_ports_;
vtr::vector<ClockTapId, std::string> tap_to_ports_;
vtr::vector<ClockTapId, vtr::Rect<size_t>>
tap_bbs_; /* Bounding box for tap points, (xlow, ylow) -> (xhigh, yhigh) */
vtr::vector<ClockTapId, vtr::Point<size_t>>
tap_bb_steps_; /* x() -> x-direction step, y() -> y-direction step */
/* Default routing resource */
std::string default_segment_name_; /* The routing segment representing the
clock wires */
RRSegmentId default_segment_id_;
std::string
default_switch_name_; /* The routing switch interconnecting clock wire */
RRSwitchId default_switch_id_;
std::string default_tap_switch_name_; /* The routing switch interconnecting
clock wire */
RRSwitchId default_tap_switch_id_;
std::string default_driver_switch_name_; /* The routing switch interconnecting
clock wire */
RRSwitchId default_driver_switch_id_;
/* Fast lookup */
std::map<std::string, ClockTreeId> tree_name2id_map_;
std::map<std::string, ClockSpineId> spine_name2id_map_;
/* Constants */
vtr::Rect<size_t> empty_tap_bb_;
/* Flags */
mutable bool is_dirty_;
};

View File

@ -19,12 +19,16 @@ struct clock_tree_id_tag;
struct clock_tree_pin_id_tag;
struct clock_spine_id_tag;
struct clock_switch_point_id_tag;
struct clock_internal_driver_id_tag;
struct clock_tap_id_tag;
typedef vtr::StrongId<clock_level_id_tag> ClockLevelId;
typedef vtr::StrongId<clock_tree_id_tag> ClockTreeId;
typedef vtr::StrongId<clock_tree_pin_id_tag> ClockTreePinId;
typedef vtr::StrongId<clock_spine_id_tag> ClockSpineId;
typedef vtr::StrongId<clock_switch_point_id_tag> ClockSwitchPointId;
typedef vtr::StrongId<clock_internal_driver_id_tag> ClockInternalDriverId;
typedef vtr::StrongId<clock_tap_id_tag> ClockTapId;
/* Short declaration of class */
class ClockNetwork;

View File

@ -10,7 +10,8 @@ RRClockSpatialLookup::RRClockSpatialLookup() {}
RRNodeId RRClockSpatialLookup::find_node(int x, int y, const ClockTreeId& tree,
const ClockLevelId& lvl,
const ClockTreePinId& pin,
const Direction& direction) const {
const Direction& direction,
const bool& verbose) const {
size_t dir = size_t(direction);
/* Pre-check: the x, y, side and ptc should be non negative numbers!
* Otherwise, return an invalid id */
@ -25,33 +26,33 @@ RRNodeId RRClockSpatialLookup::find_node(int x, int y, const ClockTreeId& tree,
* - Return an invalid id if any out-of-range is detected
*/
if (size_t(dir) >= rr_node_indices_.size()) {
VTR_LOG("Direction out of range");
VTR_LOGV(verbose, "Direction out of range\n");
return RRNodeId::INVALID();
}
if (size_t(x) >= rr_node_indices_[dir].dim_size(0)) {
VTR_LOG("X out of range");
VTR_LOGV(verbose, "X out of range\n");
return RRNodeId::INVALID();
}
if (size_t(y) >= rr_node_indices_[dir].dim_size(1)) {
VTR_LOG("Y out of range");
VTR_LOG("Y out of range\n");
return RRNodeId::INVALID();
}
if (size_t(tree) >= rr_node_indices_[dir][x][y].size()) {
VTR_LOG("Tree id out of range");
VTR_LOGV(verbose, "Tree id out of range\n");
return RRNodeId::INVALID();
}
if (size_t(lvl) == rr_node_indices_[dir][x][y][size_t(tree)].size()) {
VTR_LOG("Level id out of range");
VTR_LOGV(verbose, "Level id out of range\n");
return RRNodeId::INVALID();
}
if (size_t(pin) ==
rr_node_indices_[dir][x][y][size_t(tree)][size_t(lvl)].size()) {
VTR_LOG("Pin id out of range");
VTR_LOGV(verbose, "Pin id out of range\n");
return RRNodeId::INVALID();
}

View File

@ -58,7 +58,7 @@ class RRClockSpatialLookup {
*/
RRNodeId find_node(int x, int y, const ClockTreeId& tree,
const ClockLevelId& lvl, const ClockTreePinId& pin,
const Direction& direction) const;
const Direction& direction, const bool& verbose) const;
/* -- Mutators -- */
public:

View File

@ -6,11 +6,13 @@
constexpr const char* XML_CLOCK_NETWORK_ROOT_NAME = "clock_networks";
constexpr const char* XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_SEGMENT =
"default_segment";
constexpr const char* XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_SWITCH =
"default_switch";
constexpr const char* XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_TAP_SWITCH =
"default_tap_switch";
constexpr const char* XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_DRIVER_SWITCH =
"default_driver_switch";
constexpr const char* XML_CLOCK_TREE_NODE_NAME = "clock_network";
constexpr const char* XML_CLOCK_TREE_ATTRIBUTE_NAME = "name";
constexpr const char* XML_CLOCK_TREE_ATTRIBUTE_WIDTH = "width";
constexpr const char* XML_CLOCK_TREE_ATTRIBUTE_GLOBAL_PORT = "global_port";
constexpr const char* XML_CLOCK_SPINE_NODE_NAME = "spine";
constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_NAME = "name";
constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_START_X = "start_x";
@ -19,12 +21,38 @@ constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_END_X = "end_x";
constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_END_Y = "end_y";
constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_TYPE = "type";
constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_DIRECTION = "direction";
constexpr const char* XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_NODE_NAME =
"intermediate_driver";
constexpr const char* XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_TAP_NODE_NAME = "tap";
constexpr const char* XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_X = "x";
constexpr const char* XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_Y = "y";
constexpr const char* XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_FROM_PIN =
"from_pin";
constexpr const char* XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_TO_PIN =
"to_pin";
constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_NODE_NAME = "switch_point";
constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_NODE_NAME =
"internal_driver";
constexpr const char*
XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_ATTRIBUTE_FROM_PIN = "from_pin";
constexpr const char*
XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_ATTRIBUTE_TO_PIN = "to_pin";
constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_TAP = "tap";
constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_X = "x";
constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_Y = "y";
constexpr const char* XML_CLOCK_TREE_TAPS_NODE_NAME = "taps";
constexpr const char* XML_CLOCK_TREE_TAP_NODE_NAME = "tap";
constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_TILE_PIN = "tile_pin";
constexpr const char* XML_CLOCK_TREE_TAP_ALL_NODE_NAME = "all";
constexpr const char* XML_CLOCK_TREE_TAP_REGION_NODE_NAME = "region";
constexpr const char* XML_CLOCK_TREE_TAP_SINGLE_NODE_NAME = "single";
constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN = "from_pin";
constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN = "to_pin";
constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_X = "x";
constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_Y = "y";
constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTX = "start_x";
constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTY = "start_y";
constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDX = "end_x";
constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDY = "end_y";
constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_REPEATX = "repeat_x";
constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_REPEATY = "repeat_y";
#endif

View File

@ -25,21 +25,107 @@
namespace openfpga { // Begin namespace openfpga
/********************************************************************
* Parse XML codes of a <tap> to an object of ClockNetwork
* Parse XML codes of a <all> to an object of ClockNetwork
*******************************************************************/
static void read_xml_clock_tree_tap(pugi::xml_node& xml_tap,
const pugiutil::loc_data& loc_data,
ClockNetwork& clk_ntwk,
const ClockTreeId& tree_id) {
static void read_xml_clock_tree_tap_type_all(pugi::xml_node& xml_tap,
const pugiutil::loc_data& loc_data,
ClockNetwork& clk_ntwk,
const ClockTreeId& tree_id) {
if (!clk_ntwk.valid_tree_id(tree_id)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_tap),
"Invalid id of a clock tree!\n");
}
std::string tile_pin_name =
get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_TILE_PIN, loc_data)
std::string from_pin_name =
get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN, loc_data)
.as_string();
clk_ntwk.add_tree_tap(tree_id, tile_pin_name);
std::string to_pin_name =
get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN, loc_data)
.as_string();
PortParser from_port_parser(from_pin_name);
clk_ntwk.add_tree_tap(tree_id, from_port_parser.port(), to_pin_name);
}
/********************************************************************
* Parse XML codes of a <single> to an object of ClockNetwork
*******************************************************************/
static void read_xml_clock_tree_tap_type_single(
pugi::xml_node& xml_tap, const pugiutil::loc_data& loc_data,
ClockNetwork& clk_ntwk, const ClockTreeId& tree_id) {
if (!clk_ntwk.valid_tree_id(tree_id)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_tap),
"Invalid id of a clock tree!\n");
}
std::string from_pin_name =
get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN, loc_data)
.as_string();
std::string to_pin_name =
get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN, loc_data)
.as_string();
PortParser from_port_parser(from_pin_name);
ClockTapId tap_id =
clk_ntwk.add_tree_tap(tree_id, from_port_parser.port(), to_pin_name);
/* Single tap only require a coordinate */
size_t tap_x = get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_X,
loc_data, pugiutil::ReqOpt::REQUIRED)
.as_int();
size_t tap_y = get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_Y,
loc_data, pugiutil::ReqOpt::REQUIRED)
.as_int();
clk_ntwk.set_tap_bounding_box(tap_id,
vtr::Rect<size_t>(tap_x, tap_y, tap_x, tap_y));
}
/********************************************************************
* Parse XML codes of a <region> to an object of ClockNetwork
*******************************************************************/
static void read_xml_clock_tree_tap_type_region(
pugi::xml_node& xml_tap, const pugiutil::loc_data& loc_data,
ClockNetwork& clk_ntwk, const ClockTreeId& tree_id) {
if (!clk_ntwk.valid_tree_id(tree_id)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_tap),
"Invalid id of a clock tree!\n");
}
std::string from_pin_name =
get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN, loc_data)
.as_string();
std::string to_pin_name =
get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN, loc_data)
.as_string();
PortParser from_port_parser(from_pin_name);
ClockTapId tap_id =
clk_ntwk.add_tree_tap(tree_id, from_port_parser.port(), to_pin_name);
/* Region require a bounding box */
size_t tap_start_x =
get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTX, loc_data,
pugiutil::ReqOpt::REQUIRED)
.as_int();
size_t tap_start_y =
get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTY, loc_data,
pugiutil::ReqOpt::REQUIRED)
.as_int();
size_t tap_end_x = get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDX,
loc_data, pugiutil::ReqOpt::REQUIRED)
.as_int();
size_t tap_end_y = get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDY,
loc_data, pugiutil::ReqOpt::REQUIRED)
.as_int();
clk_ntwk.set_tap_bounding_box(
tap_id, vtr::Rect<size_t>(tap_start_x, tap_start_y, tap_end_x, tap_end_y));
/* Default step is all 1 */
size_t tap_step_x =
get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_REPEATX, loc_data)
.as_int(1);
size_t tap_step_y =
get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_REPEATY, loc_data)
.as_int(1);
clk_ntwk.set_tap_step_x(tap_id, tap_step_x);
clk_ntwk.set_tap_step_y(tap_id, tap_step_y);
}
static void read_xml_clock_tree_taps(pugi::xml_node& xml_taps,
@ -48,14 +134,76 @@ static void read_xml_clock_tree_taps(pugi::xml_node& xml_taps,
const ClockTreeId& tree_id) {
for (pugi::xml_node xml_tap : xml_taps.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_tap.name() == std::string(XML_CLOCK_TREE_TAP_NODE_NAME)) {
read_xml_clock_tree_tap(xml_tap, loc_data, clk_ntwk, tree_id);
if (xml_tap.name() == std::string(XML_CLOCK_TREE_TAP_ALL_NODE_NAME)) {
read_xml_clock_tree_tap_type_all(xml_tap, loc_data, clk_ntwk, tree_id);
} else if (xml_tap.name() ==
std::string(XML_CLOCK_TREE_TAP_REGION_NODE_NAME)) {
read_xml_clock_tree_tap_type_region(xml_tap, loc_data, clk_ntwk, tree_id);
} else if (xml_tap.name() ==
std::string(XML_CLOCK_TREE_TAP_SINGLE_NODE_NAME)) {
read_xml_clock_tree_tap_type_single(xml_tap, loc_data, clk_ntwk, tree_id);
} else {
bad_tag(xml_taps, loc_data, xml_tap, {XML_CLOCK_TREE_TAP_NODE_NAME});
bad_tag(
xml_taps, loc_data, xml_tap,
{XML_CLOCK_TREE_TAP_ALL_NODE_NAME, XML_CLOCK_TREE_TAP_REGION_NODE_NAME,
XML_CLOCK_TREE_TAP_SINGLE_NODE_NAME});
}
}
}
/********************************************************************
* Parse XML codes of a <switch_point> to an object of ClockNetwork
*******************************************************************/
static void read_xml_clock_spine_switch_point_internal_driver(
pugi::xml_node& xml_int_driver, const pugiutil::loc_data& loc_data,
ClockNetwork& clk_ntwk, const ClockSpineId& spine_id,
const ClockSwitchPointId& switch_point_id) {
if (!clk_ntwk.valid_spine_id(spine_id)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_int_driver),
"Invalid id of a clock spine!\n");
}
std::string int_driver_from_port_name =
get_attribute(
xml_int_driver,
XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_ATTRIBUTE_FROM_PIN, loc_data)
.as_string();
std::string int_driver_to_port_name =
get_attribute(xml_int_driver,
XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_ATTRIBUTE_TO_PIN,
loc_data)
.as_string();
clk_ntwk.add_spine_switch_point_internal_driver(spine_id, switch_point_id,
int_driver_from_port_name,
int_driver_to_port_name);
}
/********************************************************************
* Parse XML codes of a <tap> to an object of ClockNetwork
*******************************************************************/
static void read_xml_clock_spine_intermediate_driver_tap(
pugi::xml_node& xml_int_driver, const pugiutil::loc_data& loc_data,
ClockNetwork& clk_ntwk, const ClockSpineId& spine_id,
const vtr::Point<int>& spine_coord) {
if (!clk_ntwk.valid_spine_id(spine_id)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_int_driver),
"Invalid id of a clock spine!\n");
}
std::string int_driver_from_port_name =
get_attribute(xml_int_driver,
XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_FROM_PIN,
loc_data)
.as_string();
std::string int_driver_to_port_name =
get_attribute(xml_int_driver,
XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_TO_PIN,
loc_data)
.as_string();
clk_ntwk.add_spine_intermediate_driver(
spine_id, spine_coord, int_driver_from_port_name, int_driver_to_port_name);
}
/********************************************************************
* Parse XML codes of a <switch_point> to an object of ClockNetwork
*******************************************************************/
@ -90,8 +238,56 @@ static void read_xml_clock_spine_switch_point(
XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_Y, loc_data)
.as_int();
clk_ntwk.add_spine_switch_point(spine_id, tap_spine_id,
vtr::Point<int>(tap_x, tap_y));
ClockSwitchPointId switch_point_id = clk_ntwk.add_spine_switch_point(
spine_id, tap_spine_id, vtr::Point<int>(tap_x, tap_y));
/* Add internal drivers if possible */
for (pugi::xml_node xml_int_driver : xml_switch_point.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_int_driver.name() ==
std::string(XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_NODE_NAME)) {
read_xml_clock_spine_switch_point_internal_driver(
xml_int_driver, loc_data, clk_ntwk, spine_id, switch_point_id);
} else {
bad_tag(xml_int_driver, loc_data, xml_switch_point,
{XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_NODE_NAME});
}
}
}
/********************************************************************
* Parse XML codes of a <driver> to an object of ClockNetwork
*******************************************************************/
static void read_xml_clock_spine_intermediate_driver(
pugi::xml_node& xml_driver, const pugiutil::loc_data& loc_data,
ClockNetwork& clk_ntwk, const ClockSpineId& spine_id) {
if (!clk_ntwk.valid_spine_id(spine_id)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_driver),
"Invalid id of a clock spine!\n");
}
int tap_x =
get_attribute(xml_driver, XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_X,
loc_data)
.as_int();
int tap_y =
get_attribute(xml_driver, XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_Y,
loc_data)
.as_int();
/* Add internal drivers if possible */
for (pugi::xml_node xml_int_driver : xml_driver.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_int_driver.name() ==
std::string(XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_TAP_NODE_NAME)) {
read_xml_clock_spine_intermediate_driver_tap(
xml_int_driver, loc_data, clk_ntwk, spine_id,
vtr::Point<int>(tap_x, tap_y));
} else {
bad_tag(xml_int_driver, loc_data, xml_driver,
{XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_TAP_NODE_NAME});
}
}
}
/********************************************************************
@ -198,9 +394,15 @@ static void read_xml_clock_spine(pugi::xml_node& xml_spine,
std::string(XML_CLOCK_SPINE_SWITCH_POINT_NODE_NAME)) {
read_xml_clock_spine_switch_point(xml_switch_point, loc_data, clk_ntwk,
spine_id);
} else if (xml_switch_point.name() ==
std::string(XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_NODE_NAME)) {
read_xml_clock_spine_intermediate_driver(xml_switch_point, loc_data,
clk_ntwk, spine_id);
} else {
bad_tag(xml_switch_point, loc_data, xml_spine,
{XML_CLOCK_SPINE_SWITCH_POINT_NODE_NAME});
{XML_CLOCK_SPINE_SWITCH_POINT_NODE_NAME,
XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_NODE_NAME});
}
}
}
@ -212,14 +414,18 @@ static void read_xml_clock_tree(pugi::xml_node& xml_clk_tree,
const pugiutil::loc_data& loc_data,
ClockNetwork& clk_ntwk) {
std::string clk_tree_name =
get_attribute(xml_clk_tree, XML_CLOCK_TREE_ATTRIBUTE_NAME, loc_data)
get_attribute(xml_clk_tree, XML_CLOCK_TREE_ATTRIBUTE_NAME, loc_data,
pugiutil::ReqOpt::REQUIRED)
.as_string();
std::string clk_global_port_str =
get_attribute(xml_clk_tree, XML_CLOCK_TREE_ATTRIBUTE_GLOBAL_PORT, loc_data,
pugiutil::ReqOpt::REQUIRED)
.as_string();
int clk_tree_width =
get_attribute(xml_clk_tree, XML_CLOCK_TREE_ATTRIBUTE_WIDTH, loc_data)
.as_int();
/* Create a new tree in the storage */
ClockTreeId tree_id = clk_ntwk.create_tree(clk_tree_name, clk_tree_width);
PortParser gport_parser(clk_global_port_str);
ClockTreeId tree_id =
clk_ntwk.create_tree(clk_tree_name, gport_parser.port());
if (false == clk_ntwk.valid_tree_id(tree_id)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_clk_tree),
@ -263,11 +469,17 @@ ClockNetwork read_xml_clock_network(const char* fname) {
.as_string();
clk_ntwk.set_default_segment_name(default_segment_name);
std::string default_switch_name =
get_attribute(xml_root, XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_SWITCH,
std::string default_tap_switch_name =
get_attribute(xml_root, XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_TAP_SWITCH,
loc_data)
.as_string();
clk_ntwk.set_default_switch_name(default_switch_name);
clk_ntwk.set_default_tap_switch_name(default_tap_switch_name);
std::string default_driver_switch_name =
get_attribute(xml_root, XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_DRIVER_SWITCH,
loc_data)
.as_string();
clk_ntwk.set_default_driver_switch_name(default_driver_switch_name);
size_t num_trees =
std::distance(xml_root.children().begin(), xml_root.children().end());

View File

@ -28,14 +28,66 @@ static int write_xml_clock_tree_taps(std::fstream& fp,
const ClockTreeId& tree_id) {
openfpga::write_tab_to_file(fp, 3);
fp << "<" << XML_CLOCK_TREE_TAPS_NODE_NAME << ">\n";
for (const std::string& tile_pin_name : clk_ntwk.tree_taps(tree_id)) {
openfpga::write_tab_to_file(fp, 4);
fp << "<" << XML_CLOCK_TREE_TAP_NODE_NAME << "";
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_TILE_PIN,
tile_pin_name.c_str());
fp << "/>"
<< "\n";
/* Depends on the type */
for (ClockTapId tap_id : clk_ntwk.tree_taps(tree_id)) {
switch (clk_ntwk.tap_type(tap_id)) {
case ClockNetwork::e_tap_type::ALL: {
openfpga::write_tab_to_file(fp, 4);
fp << "<" << XML_CLOCK_TREE_TAP_ALL_NODE_NAME << "";
write_xml_attribute(
fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN,
clk_ntwk.tap_from_port(tap_id).to_verilog_string().c_str());
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN,
clk_ntwk.tap_to_port(tap_id).c_str());
fp << "/>"
<< "\n";
break;
}
case ClockNetwork::e_tap_type::SINGLE: {
openfpga::write_tab_to_file(fp, 4);
fp << "<" << XML_CLOCK_TREE_TAP_SINGLE_NODE_NAME << "";
write_xml_attribute(
fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN,
clk_ntwk.tap_from_port(tap_id).to_verilog_string().c_str());
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN,
clk_ntwk.tap_to_port(tap_id).c_str());
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_X,
clk_ntwk.tap_x(tap_id));
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_Y,
clk_ntwk.tap_y(tap_id));
fp << "/>"
<< "\n";
break;
}
case ClockNetwork::e_tap_type::REGION: {
openfpga::write_tab_to_file(fp, 4);
fp << "<" << XML_CLOCK_TREE_TAP_REGION_NODE_NAME << "";
write_xml_attribute(
fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN,
clk_ntwk.tap_from_port(tap_id).to_verilog_string().c_str());
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN,
clk_ntwk.tap_to_port(tap_id).c_str());
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTX,
clk_ntwk.tap_bounding_box(tap_id).xmin());
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTY,
clk_ntwk.tap_bounding_box(tap_id).ymin());
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDX,
clk_ntwk.tap_bounding_box(tap_id).xmax());
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDY,
clk_ntwk.tap_bounding_box(tap_id).ymax());
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_REPEATX,
clk_ntwk.tap_step_x(tap_id));
write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_REPEATY,
clk_ntwk.tap_step_y(tap_id));
fp << "/>"
<< "\n";
break;
}
default: {
VTR_LOG_ERROR("Invalid type of tap point!\n");
return 1;
}
}
}
openfpga::write_tab_to_file(fp, 3);
@ -60,8 +112,67 @@ static int write_xml_clock_spine_switch_point(
write_xml_attribute(fp, XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_X, coord.x());
write_xml_attribute(fp, XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_Y, coord.y());
fp << "/>"
<< "\n";
/* Optional: internal drivers */
if (clk_ntwk.spine_switch_point_internal_drivers(spine_id, switch_point_id)
.empty()) {
fp << "/>"
<< "\n";
} else {
fp << ">"
<< "\n";
for (ClockInternalDriverId int_driver_id :
clk_ntwk.spine_switch_point_internal_drivers(spine_id,
switch_point_id)) {
openfpga::write_tab_to_file(fp, 4);
fp << "<" << XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_NODE_NAME;
write_xml_attribute(
fp, XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_ATTRIBUTE_FROM_PIN,
clk_ntwk.internal_driver_from_pin(int_driver_id).c_str());
write_xml_attribute(
fp, XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_ATTRIBUTE_TO_PIN,
clk_ntwk.internal_driver_to_pin(int_driver_id)
.to_verilog_string()
.c_str());
fp << "/>"
<< "\n";
}
fp << "</" << XML_CLOCK_SPINE_SWITCH_POINT_NODE_NAME << ">\n";
}
return 0;
}
static int write_xml_clock_spine_intermediate_drivers(
std::fstream& fp, const ClockNetwork& clk_ntwk, const ClockSpineId& spine_id,
const vtr::Point<int>& coord) {
std::vector<ClockInternalDriverId> int_drivers =
clk_ntwk.spine_intermediate_drivers(spine_id, coord);
if (int_drivers.empty()) {
return 0;
}
openfpga::write_tab_to_file(fp, 3);
fp << "<" << XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_NODE_NAME << "";
write_xml_attribute(fp, XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_X,
coord.x());
write_xml_attribute(fp, XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_Y,
coord.y());
for (ClockInternalDriverId int_driver_id : int_drivers) {
openfpga::write_tab_to_file(fp, 4);
fp << "<" << XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_TAP_NODE_NAME;
write_xml_attribute(
fp, XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_FROM_PIN,
clk_ntwk.internal_driver_from_pin(int_driver_id).c_str());
write_xml_attribute(fp,
XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_TO_PIN,
clk_ntwk.internal_driver_to_pin(int_driver_id)
.to_verilog_string()
.c_str());
fp << "/>"
<< "\n";
}
fp << "</" << XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_NODE_NAME << ">\n";
return 0;
}
@ -90,6 +201,10 @@ static int write_xml_clock_spine(std::fstream& fp, const ClockNetwork& clk_ntwk,
fp << ">"
<< "\n";
for (const vtr::Point<int>& coord : clk_ntwk.spine_coordinates(spine_id)) {
write_xml_clock_spine_intermediate_drivers(fp, clk_ntwk, spine_id, coord);
}
for (const ClockSwitchPointId& switch_point_id :
clk_ntwk.spine_switch_points(spine_id)) {
write_xml_clock_spine_switch_point(fp, clk_ntwk, spine_id, switch_point_id);
@ -126,8 +241,9 @@ static int write_xml_clock_tree(std::fstream& fp, const ClockNetwork& clk_ntwk,
write_xml_attribute(fp, XML_CLOCK_TREE_ATTRIBUTE_NAME,
clk_ntwk.tree_name(tree_id).c_str());
write_xml_attribute(fp, XML_CLOCK_TREE_ATTRIBUTE_WIDTH,
clk_ntwk.tree_width(tree_id));
write_xml_attribute(
fp, XML_CLOCK_TREE_ATTRIBUTE_GLOBAL_PORT,
clk_ntwk.tree_global_port(tree_id).to_verilog_string().c_str());
fp << ">"
<< "\n";
@ -168,8 +284,10 @@ int write_xml_clock_network(const char* fname, const ClockNetwork& clk_ntwk) {
fp << "<" << XML_CLOCK_NETWORK_ROOT_NAME;
write_xml_attribute(fp, XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_SEGMENT,
clk_ntwk.default_segment_name().c_str());
write_xml_attribute(fp, XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_SWITCH,
clk_ntwk.default_switch_name().c_str());
write_xml_attribute(fp, XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_TAP_SWITCH,
clk_ntwk.default_tap_switch_name().c_str());
write_xml_attribute(fp, XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_DRIVER_SWITCH,
clk_ntwk.default_driver_switch_name().c_str());
fp << ">"
<< "\n";

View File

@ -22,7 +22,10 @@ static int link_clock_network_rr_segments(ClockNetwork& clk_ntwk,
return CMD_EXEC_SUCCESS;
}
}
VTR_LOG_ERROR(
"Unable to find the default segement '%s' in VPR architecture "
"description!\n",
default_segment_name.c_str());
return CMD_EXEC_FATAL_ERROR;
}
@ -30,19 +33,46 @@ static int link_clock_network_rr_segments(ClockNetwork& clk_ntwk,
* Link all the switches that are defined in a routing resource graph to a given
*clock network
*******************************************************************/
static int link_clock_network_rr_switches(ClockNetwork& clk_ntwk,
const RRGraphView& rr_graph) {
/* default switch id */
std::string default_switch_name = clk_ntwk.default_switch_name();
static int link_clock_network_tap_rr_switches(ClockNetwork& clk_ntwk,
const RRGraphView& rr_graph) {
/* default tap switch id */
std::string default_tap_switch_name = clk_ntwk.default_tap_switch_name();
for (size_t rr_switch_id = 0; rr_switch_id < rr_graph.num_rr_switches();
++rr_switch_id) {
if (std::string(rr_graph.rr_switch_inf(RRSwitchId(rr_switch_id)).name) ==
default_switch_name) {
clk_ntwk.set_default_switch(RRSwitchId(rr_switch_id));
default_tap_switch_name) {
clk_ntwk.set_default_tap_switch(RRSwitchId(rr_switch_id));
return CMD_EXEC_SUCCESS;
}
}
VTR_LOG_ERROR(
"Unable to find the default tap switch '%s' in VPR architecture "
"description!\n",
default_tap_switch_name.c_str());
return CMD_EXEC_FATAL_ERROR;
}
/********************************************************************
* Link all the switches that are defined in a routing resource graph to a given
*clock network
*******************************************************************/
static int link_clock_network_driver_rr_switches(ClockNetwork& clk_ntwk,
const RRGraphView& rr_graph) {
/* default driver switch id */
std::string default_driver_switch_name =
clk_ntwk.default_driver_switch_name();
for (size_t rr_switch_id = 0; rr_switch_id < rr_graph.num_rr_switches();
++rr_switch_id) {
if (std::string(rr_graph.rr_switch_inf(RRSwitchId(rr_switch_id)).name) ==
default_driver_switch_name) {
clk_ntwk.set_default_driver_switch(RRSwitchId(rr_switch_id));
return CMD_EXEC_SUCCESS;
}
}
VTR_LOG_ERROR(
"Unable to find the default driver switch '%s' in VPR architecture "
"description!\n",
default_driver_switch_name.c_str());
return CMD_EXEC_FATAL_ERROR;
}
@ -54,7 +84,11 @@ int link_clock_network_rr_graph(ClockNetwork& clk_ntwk,
if (CMD_EXEC_FATAL_ERROR == status) {
return status;
}
status = link_clock_network_rr_switches(clk_ntwk, rr_graph);
status = link_clock_network_tap_rr_switches(clk_ntwk, rr_graph);
if (CMD_EXEC_FATAL_ERROR == status) {
return status;
}
status = link_clock_network_driver_rr_switches(clk_ntwk, rr_graph);
if (CMD_EXEC_FATAL_ERROR == status) {
return status;
}
@ -62,4 +96,39 @@ int link_clock_network_rr_graph(ClockNetwork& clk_ntwk,
return status;
}
/** Check for each global ports in tile annotation
* If a clock tree is required for a global port, the global port name define
* in the tile annotation should match the one in clock clock
*/
int check_clock_network_tile_annotation(const ClockNetwork& clk_ntwk,
const TileAnnotation& tile_annotation) {
for (const TileGlobalPortId& gport_id : tile_annotation.global_ports()) {
if (!tile_annotation.global_port_thru_dedicated_network(gport_id)) {
continue;
}
std::string gport_name = tile_annotation.global_port_name(gport_id);
std::string clk_tree_name =
tile_annotation.global_port_clock_arch_tree_name(gport_id);
ClockTreeId clk_tree_id = clk_ntwk.find_tree(clk_tree_name);
if (!clk_ntwk.valid_tree_id(clk_tree_id)) {
VTR_LOG_ERROR(
"Invalid clock tree name '%s' defined for global port '%s' in tile "
"annotation! Must be a valid name defined in the clock network "
"description!\n",
clk_tree_name.c_str(), gport_name.c_str());
return CMD_EXEC_FATAL_ERROR;
}
if (clk_ntwk.tree_global_port(clk_tree_id).get_name() != gport_name) {
VTR_LOG_ERROR(
"Global port '%s' of clock tree name '%s' must match the name of "
"assoicated global port '%s' in tile annotation! Must be a valid name "
"defined in the clock network description!\n",
clk_ntwk.tree_global_port(clk_tree_id).to_verilog_string().c_str(),
clk_tree_name.c_str(), gport_name.c_str());
return CMD_EXEC_FATAL_ERROR;
}
}
return CMD_EXEC_SUCCESS;
}
} // End of namespace openfpga

View File

@ -6,6 +6,7 @@
*******************************************************************/
#include "clock_network.h"
#include "rr_graph_view.h"
#include "tile_annotation.h"
/********************************************************************
* Function declaration
@ -16,6 +17,9 @@ namespace openfpga { // Begin namespace openfpga
int link_clock_network_rr_graph(ClockNetwork& clk_ntwk,
const RRGraphView& rr_graph);
int check_clock_network_tile_annotation(const ClockNetwork& clk_ntwk,
const TileAnnotation& tile_annotation);
} // End of namespace openfpga
#endif

Some files were not shown because too many files have changed in this diff Show More