Merge branch 'dev' into patch-2
@@ -12,7 +12,7 @@ parameters:
|
||||
executors:
|
||||
main-env:
|
||||
docker:
|
||||
- image: ucbbar/chipyard-image:1.0.1
|
||||
- image: ucbbar/chipyard-ci-image:ab57b7d
|
||||
environment:
|
||||
JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit
|
||||
|
||||
@@ -112,7 +112,7 @@ commands:
|
||||
default: "run-tests.sh"
|
||||
timeout:
|
||||
type: string
|
||||
default: "10m"
|
||||
default: "25m"
|
||||
steps:
|
||||
- setup-tools:
|
||||
tools-version: "<< parameters.tools-version >>"
|
||||
@@ -231,7 +231,7 @@ jobs:
|
||||
- run-tests:
|
||||
group-key: "group-cores"
|
||||
project-key: "chipyard-hetero"
|
||||
timeout: "15m"
|
||||
timeout: "20m"
|
||||
chipyard-boom-run-tests:
|
||||
executor: main-env
|
||||
steps:
|
||||
@@ -308,6 +308,7 @@ jobs:
|
||||
tools-version: "esp-tools"
|
||||
group-key: "group-accels"
|
||||
project-key: "chipyard-hwacha"
|
||||
timeout: "30m"
|
||||
chipyard-gemmini-run-tests:
|
||||
executor: main-env
|
||||
steps:
|
||||
@@ -520,4 +521,3 @@ workflows:
|
||||
- prepare-chipyard-fpga:
|
||||
requires:
|
||||
- install-riscv-toolchain
|
||||
|
||||
|
||||
@@ -1,216 +0,0 @@
|
||||
### Note: This DockerFile is adapted from https://github.com/CircleCI-Public/example-images/openjdk
|
||||
|
||||
FROM openjdk:11.0.1-jdk-sid
|
||||
|
||||
# man directory is missing in some base images
|
||||
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=863199
|
||||
RUN apt-get update \
|
||||
&& mkdir -p /usr/share/man/man1 \
|
||||
&& apt-get install -y \
|
||||
bzip2 \
|
||||
ca-certificates \
|
||||
curl \
|
||||
git \
|
||||
gnupg \
|
||||
gzip \
|
||||
libfl2 \
|
||||
libfl-dev \
|
||||
locales \
|
||||
mercurial \
|
||||
netcat \
|
||||
net-tools \
|
||||
openssh-client \
|
||||
parallel \
|
||||
sudo \
|
||||
tar \
|
||||
unzip \
|
||||
wget \
|
||||
xvfb \
|
||||
xxd \
|
||||
zip \
|
||||
ccache \
|
||||
libgoogle-perftools-dev \
|
||||
numactl \
|
||||
zlib1g
|
||||
|
||||
# Set timezone to UTC by default
|
||||
RUN ln -sf /usr/share/zoneinfo/Etc/UTC /etc/localtime
|
||||
|
||||
# Use unicode
|
||||
RUN locale-gen C.UTF-8 || true
|
||||
ENV LANG=C.UTF-8
|
||||
|
||||
# install jq
|
||||
RUN JQ_URL="https://circle-downloads.s3.amazonaws.com/circleci-images/cache/linux-amd64/jq-latest" \
|
||||
&& curl --silent --show-error --location --fail --retry 3 --output /usr/bin/jq $JQ_URL \
|
||||
&& chmod +x /usr/bin/jq \
|
||||
&& jq --version
|
||||
|
||||
# Install Docker
|
||||
|
||||
# Docker.com returns the URL of the latest binary when you hit a directory listing
|
||||
# We curl this URL and `grep` the version out.
|
||||
# The output looks like this:
|
||||
|
||||
#> # To install, run the following commands as root:
|
||||
#> curl -fsSLO https://download.docker.com/linux/static/stable/x86_64/docker-17.05.0-ce.tgz && tar --strip-components=1 -xvzf docker-17.05.0-ce.tgz -C /usr/local/bin
|
||||
#>
|
||||
#> # Then start docker in daemon mode:
|
||||
#> /usr/local/bin/dockerd
|
||||
|
||||
RUN set -ex \
|
||||
&& export DOCKER_VERSION=$(curl --silent --fail --retry 3 https://download.docker.com/linux/static/stable/x86_64/ | grep -o -e 'docker-[.0-9]*-ce\.tgz' | sort -r | head -n 1) \
|
||||
&& DOCKER_URL="https://download.docker.com/linux/static/stable/x86_64/${DOCKER_VERSION}" \
|
||||
&& echo Docker URL: $DOCKER_URL \
|
||||
&& curl --silent --show-error --location --fail --retry 3 --output /tmp/docker.tgz "${DOCKER_URL}" \
|
||||
&& ls -lha /tmp/docker.tgz \
|
||||
&& tar -xz -C /tmp -f /tmp/docker.tgz \
|
||||
&& mv /tmp/docker/* /usr/bin \
|
||||
&& rm -rf /tmp/docker /tmp/docker.tgz \
|
||||
&& which docker \
|
||||
&& (docker version || true)
|
||||
|
||||
# docker compose
|
||||
RUN COMPOSE_URL="https://circle-downloads.s3.amazonaws.com/circleci-images/cache/linux-amd64/docker-compose-latest" \
|
||||
&& curl --silent --show-error --location --fail --retry 3 --output /usr/bin/docker-compose $COMPOSE_URL \
|
||||
&& chmod +x /usr/bin/docker-compose \
|
||||
&& docker-compose version
|
||||
|
||||
# install dockerize
|
||||
RUN DOCKERIZE_URL="https://circle-downloads.s3.amazonaws.com/circleci-images/cache/linux-amd64/dockerize-latest.tar.gz" \
|
||||
&& curl --silent --show-error --location --fail --retry 3 --output /tmp/dockerize-linux-amd64.tar.gz $DOCKERIZE_URL \
|
||||
&& tar -C /usr/local/bin -xzvf /tmp/dockerize-linux-amd64.tar.gz \
|
||||
&& rm -rf /tmp/dockerize-linux-amd64.tar.gz \
|
||||
&& dockerize --version
|
||||
|
||||
RUN groupadd --gid 3434 riscvuser \
|
||||
&& useradd --uid 3434 --gid riscvuser --shell /bin/bash --create-home riscvuser \
|
||||
&& echo 'riscvuser ALL=NOPASSWD: ALL' >> /etc/sudoers.d/50-riscvuser \
|
||||
&& echo 'Defaults env_keep += "DEBIAN_FRONTEND"' >> /etc/sudoers.d/env_keep
|
||||
|
||||
# BEGIN IMAGE CUSTOMIZATIONS
|
||||
|
||||
# cacerts from OpenJDK 9-slim to workaround http://bugs.java.com/view_bug.do?bug_id=8189357
|
||||
# AND https://github.com/docker-library/openjdk/issues/145
|
||||
#
|
||||
# Created by running:
|
||||
# docker run --rm openjdk:9-slim cat /etc/ssl/certs/java/cacerts | # aws s3 cp - s3://circle-downloads/circleci-images/cache/linux-amd64/openjdk-9-slim-cacerts --acl public-read
|
||||
RUN if java -fullversion 2>&1 | grep -q '"9.'; then curl --silent --show-error --location --fail --retry 3 --output /etc/ssl/certs/java/cacerts https://circle-downloads.s3.amazonaws.com/circleci-images/cache/linux-amd64/openjdk-9-slim-cacerts; fi
|
||||
|
||||
# Install Maven Version: 3.6.3
|
||||
RUN curl --silent --show-error --location --fail --retry 3 --output /tmp/apache-maven.tar.gz https://www.apache.org/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz \
|
||||
&& tar xf /tmp/apache-maven.tar.gz -C /opt/ \
|
||||
&& rm /tmp/apache-maven.tar.gz \
|
||||
&& ln -s /opt/apache-maven-* /opt/apache-maven \
|
||||
&& /opt/apache-maven/bin/mvn -version
|
||||
|
||||
# Install Ant Version: 1.10.5
|
||||
RUN curl --silent --show-error --location --fail --retry 3 --output /tmp/apache-ant.tar.gz https://archive.apache.org/dist/ant/binaries/apache-ant-1.10.5-bin.tar.gz \
|
||||
&& tar xf /tmp/apache-ant.tar.gz -C /opt/ \
|
||||
&& ln -s /opt/apache-ant-* /opt/apache-ant \
|
||||
&& rm -rf /tmp/apache-ant.tar.gz \
|
||||
&& /opt/apache-ant/bin/ant -version
|
||||
|
||||
ENV ANT_HOME=/opt/apache-ant
|
||||
|
||||
# Install Gradle Version: 5.0
|
||||
RUN curl --silent --show-error --location --fail --retry 3 --output /tmp/gradle.zip https://services.gradle.org/distributions/gradle-5.0-bin.zip \
|
||||
&& unzip -d /opt /tmp/gradle.zip \
|
||||
&& rm /tmp/gradle.zip \
|
||||
&& ln -s /opt/gradle-* /opt/gradle \
|
||||
&& /opt/gradle/bin/gradle -version
|
||||
|
||||
# Install sbt from https://circle-downloads.s3.amazonaws.com/circleci-images/cache/linux-amd64/sbt-latest.tgz
|
||||
RUN curl --silent --show-error --location --fail --retry 3 --output /tmp/sbt.tgz https://circle-downloads.s3.amazonaws.com/circleci-images/cache/linux-amd64/sbt-latest.tgz \
|
||||
&& tar -xzf /tmp/sbt.tgz -C /opt/ \
|
||||
&& rm /tmp/sbt.tgz \
|
||||
&& /opt/sbt/bin/sbt sbtVersion
|
||||
|
||||
# Install openjfx
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y --no-install-recommends openjfx
|
||||
|
||||
# Add build-essential
|
||||
RUN apt-get install -y build-essential
|
||||
|
||||
# Add RISCV toolchain necessary dependencies
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y \
|
||||
autoconf \
|
||||
automake \
|
||||
autotools-dev \
|
||||
babeltrace \
|
||||
bc \
|
||||
curl \
|
||||
device-tree-compiler \
|
||||
expat \
|
||||
flex \
|
||||
gawk \
|
||||
gperf \
|
||||
g++ \
|
||||
libexpat-dev \
|
||||
libgmp-dev \
|
||||
libmpc-dev \
|
||||
libmpfr-dev \
|
||||
libtool \
|
||||
libusb-1.0-0-dev \
|
||||
make \
|
||||
patchutils \
|
||||
pkg-config \
|
||||
python \
|
||||
python-pexpect-doc \
|
||||
python3 \
|
||||
texinfo \
|
||||
zlib1g-dev \
|
||||
rsync
|
||||
|
||||
# Use specific bison version to bypass Verilator 4.034 issues
|
||||
# TODO: When Verilator is bumped, use apt to get newest bison
|
||||
RUN wget https://ftp.gnu.org/gnu/bison/bison-3.5.4.tar.gz \
|
||||
&& tar -xvf bison-3.5.4.tar.gz \
|
||||
&& cd bison-3.5.4 \
|
||||
&& ./configure && make && make install
|
||||
|
||||
# Check bison version is 3.5.4
|
||||
RUN bison --version
|
||||
|
||||
# Add minimal QEMU dependencies
|
||||
RUN apt-get install -y \
|
||||
libfdt-dev \
|
||||
libglib2.0-dev \
|
||||
libpixman-1-dev
|
||||
|
||||
# Install verilator
|
||||
RUN git clone http://git.veripool.org/git/verilator \
|
||||
&& cd verilator \
|
||||
&& git pull \
|
||||
&& git checkout v4.034 \
|
||||
&& autoconf && ./configure && make && make install
|
||||
|
||||
# Update PATH for Java tools
|
||||
ENV PATH="/opt/sbt/bin:/opt/apache-maven/bin:/opt/apache-ant/bin:/opt/gradle/bin:$PATH"
|
||||
|
||||
# Add HOME environment variable
|
||||
ENV HOME="/home/riscvuser"
|
||||
|
||||
# Update PATH for RISCV toolchain (note: hardcoded for CircleCI)
|
||||
ENV RISCV="$HOME/riscv-tools-install"
|
||||
ENV LD_LIBRARY_PATH="$RISCV/lib"
|
||||
ENV PATH="$RISCV/bin:$PATH"
|
||||
|
||||
WORKDIR $HOME
|
||||
USER riscvuser
|
||||
|
||||
# smoke test with path
|
||||
RUN mvn -version \
|
||||
&& ant -version \
|
||||
&& gradle -version \
|
||||
&& sbt sbtVersion \
|
||||
&& verilator --version
|
||||
|
||||
# remove extra folders
|
||||
RUN rm -rf project/
|
||||
|
||||
# END IMAGE CUSTOMIZATIONS
|
||||
|
||||
CMD ["/bin/sh"]
|
||||
@@ -1,18 +0,0 @@
|
||||
General
|
||||
-------
|
||||
This DockerFile contains the necessary steps to build a Docker container that can run
|
||||
projects with riscv-tools, chisel3, firrtl, and verilator. It installs the necessary
|
||||
apt-get packages and sets the environment variables needed in CircleCI.
|
||||
|
||||
Build and Deploy the Container
|
||||
------------------------------
|
||||
|
||||
sudo docker build . # to test build before building it with a tag
|
||||
sudo docker build -t <PATH_NAME>:tag . # to build with tag (ex. 0.0.3)
|
||||
sudo docker login # login into the account to push to
|
||||
sudo docker push <PATH_NAME>:tag # to push to repo with tag
|
||||
|
||||
Path Names
|
||||
----------
|
||||
Older docker images (when this Dockerfile was in `riscv-boom/riscv-boom`) can be found in the <PATH_NAME> `riscvboom/riscvboom-images`.
|
||||
Current up-to-date images are located in <PATH_NAME> `ucbbar/chipyard-image`
|
||||
4
.java_tmp/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
||||
67
dockerfiles/Dockerfile
Normal file
@@ -0,0 +1,67 @@
|
||||
### This is a full chipyard setup
|
||||
|
||||
# BUILD BASE FOR CI
|
||||
|
||||
FROM ubuntu:18.04 as base
|
||||
ARG CHIPYARD_HASH
|
||||
|
||||
MAINTAINER https://groups.google.com/forum/#!forum/chipyard
|
||||
|
||||
# Install dependencies for ubuntu-req.sh
|
||||
RUN apt-get update && \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
git \
|
||||
sudo \
|
||||
ca-certificates \
|
||||
keyboard-configuration \
|
||||
console-setup
|
||||
|
||||
# Adds a new user called riscvuser
|
||||
RUN groupadd --gid 3434 riscvuser \
|
||||
&& useradd --uid 3434 --gid riscvuser --shell /bin/bash --create-home riscvuser \
|
||||
&& echo 'riscvuser ALL=NOPASSWD: ALL' >> /etc/sudoers.d/50-riscvuser \
|
||||
&& echo 'Defaults env_keep += "DEBIAN_FRONTEND"' >> /etc/sudoers.d/env_keep
|
||||
|
||||
WORKDIR /home/riscvuser
|
||||
USER riscvuser
|
||||
|
||||
# Update PATH for RISCV toolchain (note: hardcoded for CircleCI)
|
||||
ENV RISCV="/home/riscvuser/riscv-tools-install"
|
||||
ENV LD_LIBRARY_PATH="$RISCV/lib"
|
||||
ENV PATH="$RISCV/bin:$PATH"
|
||||
|
||||
# Install Chipyard and run ubuntu-req.sh to install necessary dependencies
|
||||
RUN git clone https://github.com/ucb-bar/chipyard.git && \
|
||||
cd chipyard && \
|
||||
git checkout $CHIPYARD_HASH && \
|
||||
./scripts/ubuntu-req.sh 1>/dev/null && \
|
||||
sudo rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
# BUILD IMAGE WITH TOOLCHAINS
|
||||
|
||||
# Use above build as base
|
||||
FROM base as base-with-tools
|
||||
|
||||
# Init submodules
|
||||
RUN cd chipyard && \
|
||||
export MAKEFLAGS=-"j $(nproc)" && \
|
||||
./scripts/init-submodules-no-riscv-tools.sh 1>/dev/null
|
||||
|
||||
# Install riscv-tools
|
||||
RUN cd chipyard && \
|
||||
export MAKEFLAGS=-"j $(nproc)" && \
|
||||
./scripts/build-toolchains.sh riscv-tools 1>/dev/null
|
||||
|
||||
# Install esp-tools
|
||||
RUN cd chipyard && \
|
||||
export MAKEFLAGS=-"j $(nproc)" && \
|
||||
./scripts/build-toolchains.sh esp-tools 1>/dev/null
|
||||
|
||||
# Run script to set environment variables on entry
|
||||
ENTRYPOINT ["chipyard/scripts/entrypoint.sh"]
|
||||
|
||||
# END IMAGE CUSTOMIZATIONS
|
||||
|
||||
CMD ["/bin/sh"]
|
||||
22
dockerfiles/README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
General
|
||||
-------
|
||||
This DockerFile contains the necessary steps to build a Docker container that can run
|
||||
projects with riscv-tools, chisel3, firrtl, and verilator. When run up to the base stage, it installs the necessary
|
||||
apt-get packages and sets the environment variables needed for CircleCI. When run up to the base-with-tools stage, it initializes and installs the necessary toolchains for running simulations and testing projects.
|
||||
|
||||
Build and Deploy the Container
|
||||
------------------------------
|
||||
|
||||
sudo docker build --target base . # to build the image for the CI
|
||||
sudo docker build --target base --build-arg CHIPYARD_HASH=<COMMIT_HASH> . # to build the image for the CI from a specific chipyard commit
|
||||
sudo docker build --target base-with-tools . # to build the full image
|
||||
sudo docker tag <IMAGE_ID> <PATH_NAME>:tag . # to tag the image after the build (ex. 0.0.3)
|
||||
sudo docker login # login into the account to push to
|
||||
sudo docker push <PATH_NAME>:tag # to push to repo with tag
|
||||
sudo docker run -it <IMAGE_ID> bash # to run an interactive version of the container
|
||||
|
||||
Path Names
|
||||
----------
|
||||
Older docker images (when this Dockerfile was in `riscv-boom/riscv-boom`) can be found in the <PATH_NAME> `riscvboom/riscvboom-images`.
|
||||
Current up-to-date images are located in <PATH_NAME> `ucbbar/chipyard-image`. NOTE: Less recent images in this path may not have toolchains initialized
|
||||
Current up-to-date CI images are located in <PATH_NAME> `ucbbar/chipyard-ci-image`.
|
||||
@@ -7,7 +7,7 @@ There are two types of DUTs that can be made: `tethered` or `standalone` DUTs.
|
||||
A `tethered` DUT is where a host computer (or just host) must send transactions to the DUT to bringup a program.
|
||||
This differs from a `standalone` DUT that can bringup itself (has its own bootrom, loads programs itself, etc).
|
||||
An example of a tethered DUT is a Chipyard simulation where the host loads the test program into the DUTs memory and signals to the DUT that the program is ready to run.
|
||||
An example of a standalone DUT is a Chipyard simulation where a program can be loaded from an SDCard by default.
|
||||
An example of a standalone DUT is a Chipyard simulation where a program can be loaded from an SDCard out of reset.
|
||||
In this section, we mainly describe how to communicate to tethered DUTs.
|
||||
|
||||
There are two ways the host (otherwise known as the outside world) can communicate with a tethered Chipyard DUT:
|
||||
@@ -45,33 +45,21 @@ Using the Tethered Serial Interface (TSI)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
By default, Chipyard uses the Tethered Serial Interface (TSI) to communicate with the DUT.
|
||||
TSI protocol is an implementation of HTIF that is used to send commands to the
|
||||
RISC-V DUT. These TSI commands are simple R/W commands
|
||||
that are able to probe the DUT's memory space. During simulation, the host sends TSI commands to a
|
||||
simulation stub called ``SimSerial`` (C++ class) that resides in a ``SimSerial`` Verilog module
|
||||
(both are located in the ``generators/testchipip`` project). This ``SimSerial`` Verilog module then
|
||||
sends the TSI command recieved by the simulation stub into the DUT which then converts the TSI
|
||||
command into a TileLink request. This conversion is done by the ``SerialAdapter`` module
|
||||
(located in the ``generators/testchipip`` project). In simulation, FESVR
|
||||
resets the DUT, writes into memory the test program, and indicates to the DUT to start the program
|
||||
through an interrupt (see :ref:`customization/Boot-Process:Chipyard Boot Process`). Using TSI is currently the fastest
|
||||
mechanism to communicate with the DUT in simulation.
|
||||
|
||||
In the case of a chip tapeout bringup, TSI commands can be sent over a custom communication
|
||||
medium to communicate with the chip. For example, some Berkeley tapeouts have a FPGA
|
||||
with a RISC-V soft-core that runs FESVR. The FESVR on the soft-core sends TSI commands
|
||||
to a TSI-to-TileLink converter living on the FPGA (i.e. ``SerialAdapter``). After the transaction is
|
||||
converted to TileLink, the ``TLSerdesser`` (located in ``generators/testchipip``) serializes the
|
||||
transaction and sends it to the chip (this ``TLSerdesser`` is sometimes also referred to as a
|
||||
serial-link or serdes). Once the serialized transaction is received on the
|
||||
chip, it is deserialized and masters a bus on the chip. The following image shows this flow:
|
||||
|
||||
.. image:: ../_static/images/chip-bringup.png
|
||||
|
||||
.. note::
|
||||
The ``TLSerdesser`` can also be used as a slave (client), so it can sink memory requests from the chip
|
||||
and connect to off-chip backing memory. Or in other words, ``TLSerdesser`` creates a bi-directional TileLink
|
||||
interface.
|
||||
TSI protocol is an implementation of HTIF that is used to send commands to the RISC-V DUT.
|
||||
These TSI commands are simple R/W commands that are able to access the DUT's memory space.
|
||||
During simulation, the host sends TSI commands to a simulation stub in the test harness called ``SimSerial``
|
||||
(C++ class) that resides in a ``SimSerial`` Verilog module (both are located in the ``generators/testchipip``
|
||||
project).
|
||||
This ``SimSerial`` Verilog module then sends the TSI command recieved by the simulation stub
|
||||
to an adapter that converts the TSI command into a TileLink request.
|
||||
This conversion is done by the ``SerialAdapter`` module (located in the ``generators/testchipip`` project).
|
||||
After the transaction is converted to TileLink, the ``TLSerdesser`` (located in ``generators/testchipip``) serializes the
|
||||
transaction and sends it to the chip (this ``TLSerdesser`` is sometimes also referred to as a digital serial-link or SerDes).
|
||||
Once the serialized transaction is received on the chip, it is deserialized and masters a TileLink bus on the chip
|
||||
which handles the request.
|
||||
In simulation, FESVR resets the DUT, writes into memory the test program, and indicates to the DUT to start the program
|
||||
through an interrupt (see :ref:`customization/Boot-Process:Chipyard Boot Process`).
|
||||
Using TSI is currently the fastest mechanism to communicate with the DUT in simulation (compared to DMI/JTAG) and is also used by FireSim.
|
||||
|
||||
Using the Debug Module Interface (DMI)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -90,14 +78,14 @@ command into a TileLink request. This conversion is done by the DTM named ``Debu
|
||||
When the DTM receives the program to load, it starts to write the binary byte-wise into memory.
|
||||
This is considerably slower than the TSI protocol communication pipeline (i.e. ``SimSerial``/``SerialAdapter``/TileLink)
|
||||
which directly writes the program binary to memory.
|
||||
Thus, Chipyard removes the DTM by default in favor of the TSI protocol for DUT communication.
|
||||
|
||||
Starting the TSI or DMI Simulation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
All default Chipyard configurations use TSI to communicate between the simulation and the simulated SoC/DUT. Hence, when running a
|
||||
software RTL simulation, as is indicated in the :ref:`simulation/Software-RTL-Simulation:Software RTL Simulation` section, you are in-fact using TSI to communicate with the DUT. As a
|
||||
reminder, to run a software RTL simulation, run:
|
||||
All default Chipyard configurations use TSI to communicate between the simulation and the simulated SoC/DUT.
|
||||
Hence, when running a software RTL simulation, as is indicated in the
|
||||
:ref:`simulation/Software-RTL-Simulation:Software RTL Simulation` section, you are in-fact using TSI to communicate with the DUT.
|
||||
As a reminder, to run a software RTL simulation, run:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -105,11 +93,10 @@ reminder, to run a software RTL simulation, run:
|
||||
# or
|
||||
cd sims/vcs
|
||||
|
||||
make CONFIG=LargeBoomConfig run-asm-tests
|
||||
make CONFIG=RocketConfig run-asm-tests
|
||||
|
||||
FireSim FPGA-accelerated simulations use TSI by default as well.
|
||||
|
||||
If you would like to build and simulate a Chipyard configuration with a DTM configured for DMI communication, then you must tie-off the TSI interface, and instantiate the `SimDTM`. Note that we use `WithTiedOffSerial ++ WithSimDebug` instead of `WithTiedOffDebug ++ WithSimSerial`.
|
||||
If you would like to build and simulate a Chipyard configuration with a DTM configured for DMI communication,
|
||||
then you must tie-off the serial-link interface, and instantiate the `SimDTM`.
|
||||
|
||||
.. literalinclude:: ../../generators/chipyard/src/main/scala/config/RocketConfigs.scala
|
||||
:language: scala
|
||||
@@ -129,14 +116,110 @@ Then you can run simulations with the new DMI-enabled top-level and test-harness
|
||||
Using the JTAG Interface
|
||||
------------------------
|
||||
|
||||
The main way to use JTAG with a Rocket Chip based system is to instantiate the Debug Transfer Module (DTM)
|
||||
and configure it to use a JTAG interface. The default Chipyard designs instantiate the DTM and configure it
|
||||
to use JTAG. You may attach OpenOCD and GDB to any of the default JTAG-enabled designs.
|
||||
Another way to interface with the DUT is to use JTAG.
|
||||
Similar to the :ref:`Advanced-Concepts/Chip-Communication:Using the Debug Module interface (DMI)` section, in order to use the JTAG protocol,
|
||||
the DUT needs to contain a Debug Transfer Module (DTM) configured to use JTAG instead of DMI.
|
||||
Once the JTAG port is exposed, the host can communicate over JTAG to the DUT through a simulation stub
|
||||
called ``SimJTAG`` (C++ class) that resides in a ``SimJTAG`` Verilog module (both reside in the ``generators/rocket-chip`` project).
|
||||
This simulation stub creates a socket that OpenOCD and GDB can connect to when the simulation is running.
|
||||
The default Chipyard designs instantiate the DTM configured to use JTAG (i.e. ``RocketConfig``).
|
||||
|
||||
.. note::
|
||||
As mentioned, default Chipyard designs are enabled with JTAG.
|
||||
However, they also use TSI/Serialized-TL with FESVR in case the JTAG interface isn't used.
|
||||
This allows users to choose how to communicate with the DUT (use TSI or JTAG).
|
||||
|
||||
Debugging with JTAG
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Please refer to the following resources on how to debug with JTAG.
|
||||
Roughly the steps to debug with JTAG in simulation are as follows:
|
||||
|
||||
* https://github.com/chipsalliance/rocket-chip#-debugging-with-gdb
|
||||
* https://github.com/riscv/riscv-isa-sim#debugging-with-gdb
|
||||
1. Build a Chipyard JTAG-enabled RTL design. Remember default Chipyard designs are JTAG ready.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd sims/verilator
|
||||
# or
|
||||
cd sims/vcs
|
||||
|
||||
make CONFIG=RocketConfig
|
||||
|
||||
2. Run the simulation with remote bit-bang enabled. Since we hope to load/run the binary using JTAG,
|
||||
we can pass ``none`` as a binary (prevents FESVR from loading the program). (Adapted from: https://github.com/chipsalliance/rocket-chip#3-launch-the-emulator)
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# note: this uses Chipyard make invocation to run the simulation to properly wrap the simulation args
|
||||
make CONFIG=RocketConfig BINARY=none SIM_FLAGS="+jtag_rbb_enable=1 --rbb-port=9823" run-binary
|
||||
|
||||
3. `Follow the instructions here to connect to the simulation using OpenOCD + GDB. <https://github.com/chipsalliance/rocket-chip#4-launch-openocd>`__
|
||||
|
||||
.. note::
|
||||
This section was adapted from the instruction in Rocket Chip and riscv-isa-sim. For more information refer
|
||||
to that documentation: `Rocket Chip GDB Docs <https://github.com/chipsalliance/rocket-chip#-debugging-with-gdb>`__,
|
||||
`riscv-isa-sim GDB Docs <https://github.com/riscv/riscv-isa-sim#debugging-with-gdb>`__
|
||||
|
||||
Example Test Chip Bringup Communication
|
||||
---------------------------------------
|
||||
|
||||
Intro to Typical Chipyard Test Chip
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Most, if not all, Chipyard configurations are tethered using TSI (over a serial-link) and have access
|
||||
to external memory through an AXI port (backing AXI memory).
|
||||
The following image shows the DUT with these set of default signals:
|
||||
|
||||
.. image:: ../_static/images/default-chipyard-config-communication.png
|
||||
|
||||
In this setup, the serial-link is connected to the TSI/FESVR peripherals while the AXI port is connected
|
||||
to a simulated AXI memory.
|
||||
However, AXI ports tend to have many signals, and thus wires, associated with them so instead of creating an AXI port off the DUT,
|
||||
one can send the memory transactions over the bi-directional serial-link (``TLSerdesser``) so that the main
|
||||
interface to the DUT is the serial-link (which has comparatively less signals than an AXI port).
|
||||
This new setup (shown below) is a typical Chipyard test chip setup:
|
||||
|
||||
.. image:: ../_static/images/bringup-chipyard-config-communication.png
|
||||
|
||||
Simulation Setup of the Example Test Chip
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To test this type of configuration (TSI/memory transactions over the serial-link), most of the same TSI collateral
|
||||
would be used.
|
||||
The main difference is that the TileLink-to-AXI converters and simulated AXI memory resides on the other side of the
|
||||
serial-link.
|
||||
|
||||
.. image:: ../_static/images/chip-bringup-simulation.png
|
||||
|
||||
.. note::
|
||||
Here the simulated AXI memory and the converters can be in a different clock domain in the test harness
|
||||
than the reference clock of the DUT.
|
||||
For example, the DUT can be clocked at 3.2GHz while the simulated AXI memory can be clocked at 1GHz.
|
||||
This functionality is done in the harness binder that instantiates the TSI collateral, TL-to-AXI converters,
|
||||
and simulated AXI memory.
|
||||
See :ref:`Advanced-Concepts/Harness-Clocks:Creating Clocks in the Test Harness` on how to generate a clock
|
||||
in a harness binder.
|
||||
|
||||
This type of simulation setup is done in the following multi-clock configuration:
|
||||
|
||||
.. literalinclude:: ../../generators/chipyard/src/main/scala/config/RocketConfigs.scala
|
||||
:language: scala
|
||||
:start-after: DOC include start: MulticlockAXIOverSerialConfig
|
||||
:end-before: DOC include end: MulticlockAXIOverSerialConfig
|
||||
|
||||
Bringup Setup of the Example Test Chip after Tapeout
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Assuming this example test chip is taped out and now ready to be tested, we can communicate with the chip using this serial-link.
|
||||
For example, a common test setup used at Berkeley to evaluate Chipyard-based test-chips includes an FPGA running a RISC-V soft-core that is able to speak to the DUT (over an FMC).
|
||||
This RISC-V soft-core would serve as the host of the test that will run on the DUT.
|
||||
This is done by the RISC-V soft-core running FESVR, sending TSI commands to a ``SerialAdapter`` / ``TLSerdesser`` programmed on the FPGA.
|
||||
Once the commands are converted to serialized TileLink, then they can be sent over some medium to the DUT
|
||||
(like an FMC cable or a set of wires connecting FPGA outputs to the DUT board).
|
||||
Similar to simulation, if the chip requests offchip memory, it can then send the transaction back over the serial-link.
|
||||
Then the request can be serviced by the FPGA DRAM.
|
||||
The following image shows this flow:
|
||||
|
||||
.. image:: ../_static/images/chip-bringup.png
|
||||
|
||||
In fact, this exact type of bringup setup is what the following section discusses:
|
||||
:ref:`Prototyping/VCU118:Introduction to the Bringup Platform`.
|
||||
|
||||
38
docs/Advanced-Concepts/Harness-Clocks.rst
Normal file
@@ -0,0 +1,38 @@
|
||||
.. _harness-clocks:
|
||||
|
||||
Creating Clocks in the Test Harness
|
||||
===================================
|
||||
|
||||
Chipyard currently allows the SoC design (everything under ``ChipTop``) to
|
||||
have independent clock domains through diplomacy.
|
||||
This implies that some reference clock enters the ``ChipTop`` and then is divided down into
|
||||
separate clock domains.
|
||||
From the perspective of the ``TestHarness`` module, the ``ChipTop`` clock and reset is
|
||||
provided from a clock and reset called ``buildtopClock`` and ``buildtopReset``.
|
||||
In the default case, this ``buildtopClock`` and ``buildtopReset`` is directly wired to the
|
||||
clock and reset IO's of the ``TestHarness`` module.
|
||||
However, the ``TestHarness`` has the ability to generate a standalone clock and reset signal
|
||||
that is separate from the reference clock/reset of ``ChipTop``.
|
||||
This allows harness components (including harness binders) the ability to "request" a clock
|
||||
for a new clock domain.
|
||||
This is useful for simulating systems in which modules in the harness have independent clock domains
|
||||
from the DUT.
|
||||
|
||||
Requests for a harness clock is done by the ``HarnessClockInstantiator`` class in ``generators/chipyard/src/main/scala/TestHarness.scala``.
|
||||
This class is accessed in harness components by referencing the Rocket Chip parameters key ``p(HarnessClockInstantiatorKey)``.
|
||||
Then you can request a clock and syncronized reset at a particular frequency by invoking the ``requestClockBundle`` function.
|
||||
Take the following example:
|
||||
|
||||
.. literalinclude:: ../../generators/chipyard/src/main/scala/HarnessBinders.scala
|
||||
:language: scala
|
||||
:start-after: DOC include start: HarnessClockInstantiatorEx
|
||||
:end-before: DOC include end: HarnessClockInstantiatorEx
|
||||
|
||||
Here you can see the ``p(HarnessClockInstantiatorKey)`` is used to request a clock and reset at ``memFreq`` frequency.
|
||||
|
||||
.. note::
|
||||
In the case that the reference clock entering ``ChipTop`` is not the overall reference clock of the simulation
|
||||
(i.e. the clock/reset coming into the ``TestHarness`` module), the ``buildtopClock`` and ``buildtopReset`` can
|
||||
differ from the implicit ``TestHarness`` clock and reset. For example, if the ``ChipTop`` reference is 500MHz but an
|
||||
extra harness clock is requested at 1GHz, the ``TestHarness`` implicit clock/reset will be at 1GHz while the ``buildtopClock``
|
||||
and ``buildtopReset`` will be at 500MHz.
|
||||
@@ -14,4 +14,5 @@ They expect you to know about Chisel, Parameters, configs, etc.
|
||||
Debugging-BOOM
|
||||
Resources
|
||||
CDEs
|
||||
Harness-Clocks
|
||||
|
||||
|
||||
@@ -66,6 +66,22 @@ You can put this in your ``.bashrc`` or equivalent environment setup file to get
|
||||
|
||||
These variables need to be set for the ``make`` system to work properly.
|
||||
|
||||
Pre-built Docker Image
|
||||
-------------------------------------------
|
||||
|
||||
An alternative to setting up the Chipyard repository locally is to pull the pre-built Docker image from Docker Hub. The image comes with all dependencies installed, Chipyard cloned, and toolchains initialized. This image sets up baseline Chipyard (not including FireMarshal, FireSim, and Hammer initializations). Each image comes with a tag that corresponds to the version of Chipyard cloned/set-up in that image. Not including a tag during the pull will pull the image with the latest version of Chipyard.
|
||||
First, pull the Docker image. Run:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
sudo docker pull ucbbar/chipyard-image:<TAG>
|
||||
|
||||
To run the Docker container in an interactive shell, run:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
sudo docker run -it ucbbar/chipyard-image bash
|
||||
|
||||
What's Next?
|
||||
-------------------------------------------
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ The following example shows a dual core BOOM with a single core Rocket.
|
||||
|
||||
.. literalinclude:: ../../generators/chipyard/src/main/scala/config/HeteroConfigs.scala
|
||||
:language: scala
|
||||
:start-after: DOC include start: DualBoomAndRocket
|
||||
:end-before: DOC include end: DualBoomAndRocket
|
||||
:start-after: DOC include start: DualBoomAndSingleRocket
|
||||
:end-before: DOC include end: DualBoomAndSingleRocket
|
||||
|
||||
|
||||
Adding Hwachas
|
||||
@@ -48,7 +48,7 @@ An example is shown below with two BOOM cores, and one Rocket tile with a RoCC a
|
||||
:start-after: DOC include start: DualBoomAndRocketOneHwacha
|
||||
:end-before: DOC include end: DualBoomAndRocketOneHwacha
|
||||
|
||||
The ``WithMultiRoCCHwacha`` config fragment assigns a Hwacha accelerator to a particular ``hartId`` (in this case, the ``hartId`` of ``2`` corresponds to the Rocket core).
|
||||
The ``WithMultiRoCCHwacha`` config fragment assigns a Hwacha accelerator to a particular ``hartId`` (in this case, the ``hartId`` of ``0`` corresponds to the Rocket core).
|
||||
Finally, the ``WithMultiRoCC`` config fragment is called.
|
||||
This config fragment sets the ``BuildRoCC`` key to use the ``MultiRoCCKey`` instead of the default.
|
||||
This must be used after all the RoCC parameters are set because it needs to override the ``BuildRoCC`` parameter.
|
||||
@@ -56,6 +56,29 @@ If this is used earlier in the configuration sequence, then MultiRoCC does not w
|
||||
|
||||
This config fragment can be changed to put more accelerators on more cores by changing the arguments to cover more ``hartId``'s (i.e. ``WithMultiRoCCHwacha(0,1,3,6,...)``).
|
||||
|
||||
Since config fragments are applied from right-to-left (or bottom-to-top as they are formatted here), the right-most config fragment specifying a core (which is ``freechips.rocketchip.subsystem.WithNBigCores`` in the example above) gets the first hart ID.
|
||||
Consider this config:
|
||||
|
||||
.. code-block:: scala
|
||||
|
||||
class RocketThenBoomHartIdTestConfig extends Config(
|
||||
new boom.common.WithNLargeBooms(2) ++
|
||||
new freechips.rocketchip.subsystem.WithNBigCores(3) ++
|
||||
new chipyard.config.AbstractConfig)
|
||||
|
||||
This specifies an SoC with three Rocket cores and two BOOM cores.
|
||||
The Rocket cores would have hart IDs 0, 1, and 2, while the BOOM cores would have hard IDs 3 and 4.
|
||||
On the other hand, consider this config which reverses the order of those two fragments:
|
||||
|
||||
.. code-block:: scala
|
||||
|
||||
class BoomThenRocketHartIdTestConfig extends Config(
|
||||
new freechips.rocketchip.subsystem.WithNBigCores(3) ++
|
||||
new boom.common.WithNLargeBooms(2) ++
|
||||
new chipyard.config.AbstractConfig)
|
||||
|
||||
This also specifies an SoC with three Rocket cores and two BOOM cores, but because the BOOM config fragment is evaluated before the Rocket config fragment, the hart IDs are reversed.
|
||||
The BOOM cores would have hart IDs 0 and 1, while the Rocket cores would have hard IDs 2, 3, and 4.
|
||||
|
||||
.. [1] Note, in this section "core" and "tile" are used interchangeably but there is subtle distinction between a "core" and "tile" ("tile" contains a "core", L1D/I$, PTW).
|
||||
For many places in the documentation, we usually use "core" to mean "tile" (doesn't make a large difference but worth the mention).
|
||||
|
||||
@@ -102,7 +102,7 @@ Separating the Top module from the TestHarness module
|
||||
|
||||
Unlike the FireSim and Software simulation flows, a VLSI flow needs to separate the test harness and the chip (a.k.a. DUT) into separate files.
|
||||
This is necessary to facilitate post-synthesis and post-place-and-route simulation, as the module names in the RTL and gate-level verilog files would collide.
|
||||
Simulations after you the design goes through a VLSI flow will use the verilog netlist generated from the flow and will need an untouched test harness to drive it.
|
||||
Simulations, after your design goes through a VLSI flow, will use the verilog netlist generated from the flow and will need an untouched test harness to drive it.
|
||||
Separating these components into separate files makes this straightforward.
|
||||
Without the separation the file that included the test harness would also redefine the DUT which is often disallowed in simulation tools.
|
||||
To do this, there is a FIRRTL ``App`` in :ref:`Tools/Barstools:Barstools` called ``GenerateTopAndHarness``, which runs the appropriate transforms to elaborate the modules separately.
|
||||
|
||||
BIN
docs/_static/images/bringup-chipyard-config-communication.png
vendored
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
docs/_static/images/chip-bringup-simulation.png
vendored
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
docs/_static/images/chip-bringup.png
vendored
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 30 KiB |
BIN
docs/_static/images/chip-communication.png
vendored
|
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 83 KiB |
BIN
docs/_static/images/default-chipyard-config-communication.png
vendored
Normal file
|
After Width: | Height: | Size: 17 KiB |
@@ -13,6 +13,7 @@ import sifive.blocks.devices.pinctrl._
|
||||
import sifive.fpgashells.ip.xilinx.{IBUFG, IOBUF, PULLUP, PowerOnResetFPGAOnly}
|
||||
|
||||
import chipyard.harness.{ComposeHarnessBinder, OverrideHarnessBinder}
|
||||
import chipyard.iobinders.JTAGChipIO
|
||||
|
||||
class WithArtyResetHarnessBinder extends ComposeHarnessBinder({
|
||||
(system: HasPeripheryDebugModuleImp, th: ArtyFPGATestHarness, ports: Seq[Bool]) => {
|
||||
@@ -31,11 +32,18 @@ class WithArtyResetHarnessBinder extends ComposeHarnessBinder({
|
||||
class WithArtyJTAGHarnessBinder extends OverrideHarnessBinder({
|
||||
(system: HasPeripheryDebug, th: ArtyFPGATestHarness, ports: Seq[Data]) => {
|
||||
ports.map {
|
||||
case j: JTAGIO =>
|
||||
withClockAndReset(th.harnessClock, th.hReset) {
|
||||
case j: JTAGChipIO =>
|
||||
withClockAndReset(th.buildtopClock, th.hReset) {
|
||||
val jtag_wire = Wire(new JTAGIO)
|
||||
jtag_wire.TDO.data := j.TDO
|
||||
jtag_wire.TDO.driven := true.B
|
||||
j.TCK := jtag_wire.TCK
|
||||
j.TMS := jtag_wire.TMS
|
||||
j.TDI := jtag_wire.TDI
|
||||
|
||||
val io_jtag = Wire(new JTAGPins(() => new BasePin(), false)).suggestName("jtag")
|
||||
|
||||
JTAGPinsFromPort(io_jtag, j)
|
||||
JTAGPinsFromPort(io_jtag, jtag_wire)
|
||||
|
||||
io_jtag.TCK.i.ival := IBUFG(IOBUF(th.jd_2).asClock).asBool
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ class ArtyFPGATestHarness(override implicit val p: Parameters) extends ArtyShell
|
||||
val dut = Module(lazyDut.module)
|
||||
}
|
||||
|
||||
val harnessClock = clock_32MHz
|
||||
val harnessReset = hReset
|
||||
val buildtopClock = clock_32MHz
|
||||
val buildtopReset = hReset
|
||||
val success = false.B
|
||||
|
||||
val dutReset = dReset
|
||||
|
||||
@@ -121,13 +121,13 @@ class VCU118FPGATestHarnessImp(_outer: VCU118FPGATestHarness) extends LazyRawMod
|
||||
val hReset = Wire(Reset())
|
||||
hReset := _outer.dutClock.in.head._1.reset
|
||||
|
||||
val harnessClock = _outer.dutClock.in.head._1.clock
|
||||
val harnessReset = WireInit(hReset)
|
||||
val buildtopClock = _outer.dutClock.in.head._1.clock
|
||||
val buildtopReset = WireInit(hReset)
|
||||
val dutReset = hReset.asAsyncReset
|
||||
val success = false.B
|
||||
|
||||
childClock := harnessClock
|
||||
childReset := harnessReset
|
||||
childClock := buildtopClock
|
||||
childReset := buildtopReset
|
||||
|
||||
// harness binders are non-lazy
|
||||
_outer.topDesign match { case d: HasTestHarnessFunctions =>
|
||||
|
||||
@@ -3,21 +3,21 @@ package chipyard.fpga.vcu118.bringup
|
||||
import scala.collection.mutable.{LinkedHashMap}
|
||||
|
||||
object BringupGPIOs {
|
||||
// map of the pin name (akin to die pin name) to (fpga package pin, IOSTANDARD)
|
||||
// map of the pin name (akin to die pin name) to (fpga package pin, IOSTANDARD, add pullup resistor?)
|
||||
val pinMapping = LinkedHashMap(
|
||||
// these connect to LEDs and switches on the VCU118 (and use 1.2V)
|
||||
"led0" -> ("AT32", "LVCMOS12"), // 0
|
||||
"led1" -> ("AV34", "LVCMOS12"), // 1
|
||||
"led2" -> ("AY30", "LVCMOS12"), // 2
|
||||
"led3" -> ("BB32", "LVCMOS12"), // 3
|
||||
"led4" -> ("BF32", "LVCMOS12"), // 4
|
||||
"led5" -> ("AU37", "LVCMOS12"), // 5
|
||||
"led6" -> ("AV36", "LVCMOS12"), // 6
|
||||
"led7" -> ("BA37", "LVCMOS12"), // 7
|
||||
"sw0" -> ("B17", "LVCMOS12"), // 8
|
||||
"sw1" -> ("G16", "LVCMOS12"), // 9
|
||||
"sw2" -> ("J16", "LVCMOS12"), // 10
|
||||
"sw3" -> ("D21", "LVCMOS12") // 11
|
||||
"led0" -> ("AT32", "LVCMOS12", false), // 0
|
||||
"led1" -> ("AV34", "LVCMOS12", false), // 1
|
||||
"led2" -> ("AY30", "LVCMOS12", false), // 2
|
||||
"led3" -> ("BB32", "LVCMOS12", false), // 3
|
||||
"led4" -> ("BF32", "LVCMOS12", false), // 4
|
||||
"led5" -> ("AU37", "LVCMOS12", false), // 5
|
||||
"led6" -> ("AV36", "LVCMOS12", false), // 6
|
||||
"led7" -> ("BA37", "LVCMOS12", false), // 7
|
||||
"sw0" -> ("B17", "LVCMOS12", false), // 8
|
||||
"sw1" -> ("G16", "LVCMOS12", false), // 9
|
||||
"sw2" -> ("J16", "LVCMOS12", false), // 10
|
||||
"sw3" -> ("D21", "LVCMOS12", false) // 11
|
||||
)
|
||||
|
||||
// return list of names (ordered)
|
||||
|
||||
@@ -94,14 +94,15 @@ class BringupGPIOVCU118PlacedOverlay(val shell: VCU118ShellBasicOverlays, name:
|
||||
require(gpioNames.length == io.gpio.length)
|
||||
|
||||
val packagePinsWithIOStdWithPackageIOs = (gpioNames zip io.gpio).map { case (name, io) =>
|
||||
val (pin, iostd) = BringupGPIOs.pinMapping(name)
|
||||
(pin, iostd, IOPin(io))
|
||||
val (pin, iostd, pullupEnable) = BringupGPIOs.pinMapping(name)
|
||||
(pin, iostd, pullupEnable, IOPin(io))
|
||||
}
|
||||
|
||||
packagePinsWithIOStdWithPackageIOs foreach { case (pin, iostd, io) => {
|
||||
packagePinsWithIOStdWithPackageIOs foreach { case (pin, iostd, pullupEnable, io) => {
|
||||
shell.xdc.addPackagePin(io, pin)
|
||||
shell.xdc.addIOStandard(io, iostd)
|
||||
if (iostd == "LVCMOS12") { shell.xdc.addDriveStrength(io, "8") }
|
||||
if (pullupEnable) { shell.xdc.addPullup(io) }
|
||||
} }
|
||||
} }
|
||||
}
|
||||
|
||||
@@ -15,6 +15,9 @@ import barstools.iocell.chisel._
|
||||
|
||||
case object BuildSystem extends Field[Parameters => LazyModule]((p: Parameters) => new DigitalTop()(p))
|
||||
|
||||
trait HasReferenceClockFreq {
|
||||
def refClockFreqMHz: Double
|
||||
}
|
||||
|
||||
/**
|
||||
* The base class used for building chips. This constructor instantiates a module specified by the BuildSystem parameter,
|
||||
@@ -24,15 +27,16 @@ case object BuildSystem extends Field[Parameters => LazyModule]((p: Parameters)
|
||||
*/
|
||||
|
||||
class ChipTop(implicit p: Parameters) extends LazyModule with BindingScope
|
||||
with HasTestHarnessFunctions with HasIOBinders {
|
||||
with HasTestHarnessFunctions with HasReferenceClockFreq with HasIOBinders {
|
||||
// The system module specified by BuildSystem
|
||||
lazy val lazySystem = LazyModule(p(BuildSystem)(p)).suggestName("system")
|
||||
|
||||
// The implicitClockSinkNode provides the implicit clock and reset for the System
|
||||
// The implicitClockSinkNode provides the implicit clock and reset for the system (connected by clocking scheme)
|
||||
val implicitClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters(name = Some("implicit_clock"))))
|
||||
|
||||
// Generate Clocks and Reset
|
||||
p(ClockingSchemeKey)(this)
|
||||
val mvRefClkFreq = p(ClockingSchemeKey)(this)
|
||||
def refClockFreqMHz: Double = mvRefClkFreq.getWrappedValue
|
||||
|
||||
// NOTE: Making this a LazyRawModule is moderately dangerous, as anonymous children
|
||||
// of ChipTop (ex: ClockGroup) do not receive clock or reset.
|
||||
|
||||
@@ -7,25 +7,26 @@ import scala.collection.mutable.{ArrayBuffer}
|
||||
import freechips.rocketchip.prci._
|
||||
import freechips.rocketchip.subsystem.{BaseSubsystem, SubsystemDriveAsyncClockGroupsKey, InstantiatesTiles}
|
||||
import freechips.rocketchip.config.{Parameters, Field, Config}
|
||||
import freechips.rocketchip.diplomacy.{OutwardNodeHandle, InModuleBody, LazyModule}
|
||||
import freechips.rocketchip.diplomacy.{ModuleValue, OutwardNodeHandle, InModuleBody, LazyModule}
|
||||
import freechips.rocketchip.util.{ResetCatchAndSync}
|
||||
|
||||
import barstools.iocell.chisel._
|
||||
import testchipip.{TLTileResetCtrl}
|
||||
|
||||
import chipyard.clocking._
|
||||
import chipyard.iobinders._
|
||||
|
||||
/**
|
||||
* A simple reset implementation that punches out reset ports
|
||||
* for standard Module classes. Three basic reset schemes
|
||||
* are provided. See [[GlobalResetScheme]].
|
||||
* for standard Module classes. The ChipTop reset pin is Async.
|
||||
* Synchronization is performed in the ClockGroupResetSynchronizer
|
||||
*/
|
||||
object GenerateReset {
|
||||
def apply(chiptop: ChipTop, clock: Clock): Reset = {
|
||||
implicit val p = chiptop.p
|
||||
// this needs directionality so generateIOFromSignal works
|
||||
val async_reset_wire = Wire(Input(AsyncReset()))
|
||||
val (reset_io, resetIOCell) = IOCell.generateIOFromSignal(async_reset_wire, "reset",
|
||||
val (reset_io, resetIOCell) = IOCell.generateIOFromSignal(async_reset_wire, "reset", p(IOCellKey),
|
||||
abstractResetAsAsync = true)
|
||||
|
||||
chiptop.iocells ++= resetIOCell
|
||||
@@ -38,7 +39,7 @@ object GenerateReset {
|
||||
}
|
||||
|
||||
|
||||
case object ClockingSchemeKey extends Field[ChipTop => Unit](ClockingSchemeGenerators.dividerOnlyClockGenerator)
|
||||
case object ClockingSchemeKey extends Field[ChipTop => ModuleValue[Double]](ClockingSchemeGenerators.dividerOnlyClockGenerator)
|
||||
/*
|
||||
* This is a Seq of assignment functions, that accept a clock name and return an optional frequency.
|
||||
* Functions that appear later in this seq have higher precedence that earlier ones.
|
||||
@@ -59,7 +60,7 @@ class ClockNameContainsAssignment(name: String, fMHz: Double) extends Config((si
|
||||
})
|
||||
|
||||
object ClockingSchemeGenerators {
|
||||
val dividerOnlyClockGenerator: ChipTop => Unit = { chiptop =>
|
||||
val dividerOnlyClockGenerator: ChipTop => ModuleValue[Double] = { chiptop =>
|
||||
implicit val p = chiptop.p
|
||||
|
||||
// Requires existence of undriven asyncClockGroups in subsystem
|
||||
@@ -70,31 +71,40 @@ object ClockingSchemeGenerators {
|
||||
|
||||
// Add a control register for each tile's reset
|
||||
val resetSetter = chiptop.lazySystem match {
|
||||
case sys: BaseSubsystem with InstantiatesTiles => TLTileResetCtrl(sys)
|
||||
case _ => ClockGroupEphemeralNode()
|
||||
case sys: BaseSubsystem with InstantiatesTiles => Some(TLTileResetCtrl(sys))
|
||||
case _ => None
|
||||
}
|
||||
val resetSetterResetProvider = resetSetter.map(_.tileResetProviderNode).getOrElse(ClockGroupEphemeralNode())
|
||||
|
||||
val aggregator = LazyModule(new ClockGroupAggregator("allClocks")).node
|
||||
// provides the implicit clock to the system
|
||||
(chiptop.implicitClockSinkNode
|
||||
:= ClockGroup()
|
||||
:= aggregator)
|
||||
// provides the system clock (ex. the bus clocks)
|
||||
(systemAsyncClockGroup
|
||||
:*= resetSetter
|
||||
:*= ClockGroupNamePrefixer()
|
||||
:*= aggregator)
|
||||
|
||||
val referenceClockSource = ClockSourceNode(Seq(ClockSourceParameters()))
|
||||
val dividerOnlyClkGenerator = LazyModule(new DividerOnlyClockGenerator("buildTopClockGenerator"))
|
||||
// provides all the divided clocks (from the top-level clock)
|
||||
(aggregator
|
||||
:= ClockGroupFrequencySpecifier(p(ClockFrequencyAssignersKey), p(DefaultClockFrequencyKey))
|
||||
:= ClockGroupResetSynchronizer()
|
||||
:= DividerOnlyClockGenerator()
|
||||
:= resetSetterResetProvider
|
||||
:= dividerOnlyClkGenerator.node
|
||||
:= referenceClockSource)
|
||||
|
||||
val asyncResetBroadcast = FixedClockBroadcast(None)
|
||||
resetSetter.foreach(_.asyncResetSinkNode := asyncResetBroadcast)
|
||||
val asyncResetSource = ClockSourceNode(Seq(ClockSourceParameters()))
|
||||
asyncResetBroadcast := asyncResetSource
|
||||
|
||||
InModuleBody {
|
||||
val clock_wire = Wire(Input(Clock()))
|
||||
val reset_wire = GenerateReset(chiptop, clock_wire)
|
||||
val (clock_io, clockIOCell) = IOCell.generateIOFromSignal(clock_wire, "clock")
|
||||
val (clock_io, clockIOCell) = IOCell.generateIOFromSignal(clock_wire, "clock", p(IOCellKey))
|
||||
chiptop.iocells ++= clockIOCell
|
||||
|
||||
referenceClockSource.out.unzip._1.map { o =>
|
||||
@@ -102,9 +112,17 @@ object ClockingSchemeGenerators {
|
||||
o.reset := reset_wire
|
||||
}
|
||||
|
||||
asyncResetSource.out.unzip._1.map { o =>
|
||||
o.clock := false.B.asClock // async reset broadcast network does not provide a clock
|
||||
o.reset := reset_wire
|
||||
}
|
||||
|
||||
chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => {
|
||||
clock_io := th.harnessClock
|
||||
clock_io := th.buildtopClock
|
||||
Nil })
|
||||
|
||||
// return the reference frequency
|
||||
dividerOnlyClkGenerator.module.referenceFreq
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import testchipip._
|
||||
import tracegen.{TraceGenSystem}
|
||||
|
||||
import hwacha.{Hwacha}
|
||||
import gemmini.{Gemmini, GemminiConfigs}
|
||||
import gemmini._
|
||||
|
||||
import boom.common.{BoomTileAttachParams}
|
||||
import cva6.{CVA6TileAttachParams}
|
||||
@@ -83,6 +83,17 @@ class WithMultiRoCC extends Config((site, here, up) => {
|
||||
case BuildRoCC => site(MultiRoCCKey).getOrElse(site(TileKey).hartId, Nil)
|
||||
})
|
||||
|
||||
/**
|
||||
* Assigns what was previously in the BuildRoCC key to specific harts with MultiRoCCKey
|
||||
* Must be paired with WithMultiRoCC
|
||||
*/
|
||||
class WithMultiRoCCFromBuildRoCC(harts: Int*) extends Config((site, here, up) => {
|
||||
case BuildRoCC => Nil
|
||||
case MultiRoCCKey => up(MultiRoCCKey, site) ++ harts.distinct.map { i =>
|
||||
(i -> up(BuildRoCC, site))
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Config fragment to add Hwachas to cores based on hart
|
||||
*
|
||||
@@ -108,11 +119,12 @@ class WithMultiRoCCHwacha(harts: Int*) extends Config(
|
||||
})
|
||||
)
|
||||
|
||||
class WithMultiRoCCGemmini(harts: Int*) extends Config((site, here, up) => {
|
||||
class WithMultiRoCCGemmini[T <: Data : Arithmetic, U <: Data, V <: Data](
|
||||
harts: Int*)(gemminiConfig: GemminiArrayConfig[T,U,V] = GemminiConfigs.defaultConfig) extends Config((site, here, up) => {
|
||||
case MultiRoCCKey => up(MultiRoCCKey, site) ++ harts.distinct.map { i =>
|
||||
(i -> Seq((p: Parameters) => {
|
||||
implicit val q = p
|
||||
val gemmini = LazyModule(new Gemmini(OpcodeSet.custom3, GemminiConfigs.defaultConfig))
|
||||
val gemmini = LazyModule(new Gemmini(gemminiConfig))
|
||||
gemmini
|
||||
}))
|
||||
}
|
||||
@@ -139,6 +151,16 @@ class WithNPerfCounters(n: Int = 29) extends Config((site, here, up) => {
|
||||
}
|
||||
})
|
||||
|
||||
class WithNPMPs(n: Int = 8) extends Config((site, here, up) => {
|
||||
case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map {
|
||||
case tp: RocketTileAttachParams => tp.copy(tileParams = tp.tileParams.copy(
|
||||
core = tp.tileParams.core.copy(nPMPs = n)))
|
||||
case tp: BoomTileAttachParams => tp.copy(tileParams = tp.tileParams.copy(
|
||||
core = tp.tileParams.core.copy(nPMPs = n)))
|
||||
case other => other
|
||||
}
|
||||
})
|
||||
|
||||
class WithRocketICacheScratchpad extends Config((site, here, up) => {
|
||||
case RocketTilesKey => up(RocketTilesKey, site) map { r =>
|
||||
r.copy(icache = r.icache.map(_.copy(itimAddr = Some(0x300000 + r.hartId * 0x10000))))
|
||||
@@ -193,7 +215,31 @@ class WithTLBackingMemory extends Config((site, here, up) => {
|
||||
case ExtTLMem => up(ExtMem, site) // enable TL backing memory
|
||||
})
|
||||
|
||||
class WithTileFrequency(fMHz: Double) extends ClockNameContainsAssignment("core", fMHz)
|
||||
class WithSerialTLBackingMemory extends Config((site, here, up) => {
|
||||
case ExtMem => None
|
||||
case SerialTLKey => up(SerialTLKey, site).map { k => k.copy(
|
||||
memParams = {
|
||||
val memPortParams = up(ExtMem, site).get
|
||||
require(memPortParams.nMemoryChannels == 1)
|
||||
memPortParams.master
|
||||
},
|
||||
isMemoryDevice = true
|
||||
)}
|
||||
})
|
||||
|
||||
/**
|
||||
* Mixins to define either a specific tile frequency for a single hart or all harts
|
||||
*
|
||||
* @param fMHz Frequency in MHz of the tile or all tiles
|
||||
* @param hartId Optional hartid to assign the frequency to (if unspecified default to all harts)
|
||||
*/
|
||||
class WithTileFrequency(fMHz: Double, hartId: Option[Int] = None) extends ClockNameContainsAssignment({
|
||||
hartId match {
|
||||
case Some(id) => s"tile_$id"
|
||||
case None => "tile"
|
||||
}
|
||||
},
|
||||
fMHz)
|
||||
|
||||
class WithPeripheryBusFrequencyAsDefault extends Config((site, here, up) => {
|
||||
case DefaultClockFrequencyKey => (site(PeripheryBusKey).dtsFrequency.get / (1000 * 1000)).toDouble
|
||||
|
||||
@@ -13,6 +13,8 @@ import freechips.rocketchip.devices.tilelink._
|
||||
|
||||
// DOC include start: DigitalTop
|
||||
class DigitalTop(implicit p: Parameters) extends ChipyardSystem
|
||||
with testchipip.CanHavePeripheryCustomBootPin // Enables optional custom boot pin
|
||||
with testchipip.HasPeripheryBootAddrReg // Use programmable boot address register
|
||||
with testchipip.CanHaveTraceIO // Enables optionally adding trace IO
|
||||
with testchipip.CanHaveBackingScratchpad // Enables optionally adding a backing scratchpad
|
||||
with testchipip.CanHavePeripheryBlockDevice // Enables optionally adding the block device
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package chipyard.harness
|
||||
|
||||
import chisel3._
|
||||
import chisel3.experimental.{Analog, BaseModule}
|
||||
import chisel3.util._
|
||||
import chisel3.experimental.{Analog, BaseModule, DataMirror, Direction}
|
||||
|
||||
import freechips.rocketchip.config.{Field, Config, Parameters}
|
||||
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImpLike}
|
||||
@@ -10,6 +11,7 @@ import freechips.rocketchip.devices.debug._
|
||||
import freechips.rocketchip.jtag.{JTAGIO}
|
||||
import freechips.rocketchip.system.{SimAXIMem}
|
||||
import freechips.rocketchip.subsystem._
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
import sifive.blocks.devices.gpio._
|
||||
import sifive.blocks.devices.uart._
|
||||
@@ -19,8 +21,8 @@ import barstools.iocell.chisel._
|
||||
|
||||
import testchipip._
|
||||
|
||||
import chipyard.HasHarnessSignalReferences
|
||||
import chipyard.iobinders.GetSystemParameters
|
||||
import chipyard.{HasHarnessSignalReferences, HarnessClockInstantiatorKey}
|
||||
import chipyard.iobinders.{GetSystemParameters, JTAGChipIO}
|
||||
|
||||
import tracegen.{TraceGenSystemModuleImp}
|
||||
import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvonly}
|
||||
@@ -88,21 +90,21 @@ class WithUARTAdapter extends OverrideHarnessBinder({
|
||||
|
||||
class WithSimSPIFlashModel(rdOnly: Boolean = true) extends OverrideHarnessBinder({
|
||||
(system: HasPeripherySPIFlashModuleImp, th: HasHarnessSignalReferences, ports: Seq[SPIChipIO]) => {
|
||||
SimSPIFlashModel.connect(ports, th.harnessReset, rdOnly)(system.p)
|
||||
SimSPIFlashModel.connect(ports, th.buildtopReset, rdOnly)(system.p)
|
||||
}
|
||||
})
|
||||
|
||||
class WithSimBlockDevice extends OverrideHarnessBinder({
|
||||
(system: CanHavePeripheryBlockDevice, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => {
|
||||
implicit val p: Parameters = GetSystemParameters(system)
|
||||
ports.map { b => SimBlockDevice.connect(b.clock, th.harnessReset.asBool, Some(b.bits)) }
|
||||
ports.map { b => SimBlockDevice.connect(b.clock, th.buildtopReset.asBool, Some(b.bits)) }
|
||||
}
|
||||
})
|
||||
|
||||
class WithBlockDeviceModel extends OverrideHarnessBinder({
|
||||
(system: CanHavePeripheryBlockDevice, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => {
|
||||
implicit val p: Parameters = GetSystemParameters(system)
|
||||
ports.map { b => withClockAndReset(b.clock, th.harnessReset) { BlockDeviceModel.connect(Some(b.bits)) } }
|
||||
ports.map { b => withClockAndReset(b.clock, th.buildtopReset) { BlockDeviceModel.connect(Some(b.bits)) } }
|
||||
}
|
||||
})
|
||||
|
||||
@@ -110,7 +112,7 @@ class WithLoopbackNIC extends OverrideHarnessBinder({
|
||||
(system: CanHavePeripheryIceNIC, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => {
|
||||
implicit val p: Parameters = GetSystemParameters(system)
|
||||
ports.map { n =>
|
||||
withClockAndReset(n.clock, th.harnessReset) {
|
||||
withClockAndReset(n.clock, th.buildtopReset) {
|
||||
NicLoopback.connect(Some(n.bits), p(NICKey))
|
||||
}
|
||||
}
|
||||
@@ -120,7 +122,7 @@ class WithLoopbackNIC extends OverrideHarnessBinder({
|
||||
class WithSimNetwork extends OverrideHarnessBinder({
|
||||
(system: CanHavePeripheryIceNIC, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => {
|
||||
implicit val p: Parameters = GetSystemParameters(system)
|
||||
ports.map { n => SimNetwork.connect(Some(n.bits), n.clock, th.harnessReset.asBool) }
|
||||
ports.map { n => SimNetwork.connect(Some(n.bits), n.clock, th.buildtopReset.asBool) }
|
||||
}
|
||||
})
|
||||
|
||||
@@ -137,14 +139,73 @@ class WithSimAXIMem extends OverrideHarnessBinder({
|
||||
}
|
||||
})
|
||||
|
||||
class WithBlackBoxSimMem extends OverrideHarnessBinder({
|
||||
class WithSimAXIMemOverSerialTL extends OverrideHarnessBinder({
|
||||
(system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => {
|
||||
implicit val p = chipyard.iobinders.GetSystemParameters(system)
|
||||
|
||||
p(SerialTLKey).map({ sVal =>
|
||||
require(sVal.axiMemOverSerialTLParams.isDefined)
|
||||
val axiDomainParams = sVal.axiMemOverSerialTLParams.get
|
||||
require(sVal.isMemoryDevice)
|
||||
|
||||
val memFreq = axiDomainParams.getMemFrequency(system.asInstanceOf[HasTileLinkLocations])
|
||||
|
||||
ports.map({ port =>
|
||||
// DOC include start: HarnessClockInstantiatorEx
|
||||
withClockAndReset(th.buildtopClock, th.buildtopReset) {
|
||||
val memOverSerialTLClockBundle = p(HarnessClockInstantiatorKey).requestClockBundle("mem_over_serial_tl_clock", memFreq)
|
||||
val serial_bits = SerialAdapter.asyncQueue(port, th.buildtopClock, th.buildtopReset)
|
||||
val harnessMultiClockAXIRAM = SerialAdapter.connectHarnessMultiClockAXIRAM(
|
||||
system.serdesser.get,
|
||||
serial_bits,
|
||||
memOverSerialTLClockBundle,
|
||||
th.buildtopReset)
|
||||
// DOC include end: HarnessClockInstantiatorEx
|
||||
val success = SerialAdapter.connectSimSerial(harnessMultiClockAXIRAM.module.io.tsi_ser, th.buildtopClock, th.buildtopReset.asBool)
|
||||
when (success) { th.success := true.B }
|
||||
|
||||
// connect SimDRAM from the AXI port coming from the harness multi clock axi ram
|
||||
(harnessMultiClockAXIRAM.mem_axi4 zip harnessMultiClockAXIRAM.memNode.edges.in).map { case (axi_port, edge) =>
|
||||
val memSize = sVal.memParams.size
|
||||
val lineSize = p(CacheBlockBytes)
|
||||
val mem = Module(new SimDRAM(memSize, lineSize, BigInt(memFreq.toLong), edge.bundle)).suggestName("simdram")
|
||||
mem.io.axi <> axi_port.bits
|
||||
mem.io.clock := axi_port.clock
|
||||
mem.io.reset := axi_port.reset
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
class WithBlackBoxSimMem(additionalLatency: Int = 0) extends OverrideHarnessBinder({
|
||||
(system: CanHaveMasterAXI4MemPort, th: HasHarnessSignalReferences, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => {
|
||||
val p: Parameters = chipyard.iobinders.GetSystemParameters(system)
|
||||
(ports zip system.memAXI4Node.edges.in).map { case (port, edge) =>
|
||||
val memSize = p(ExtMem).get.master.size
|
||||
val lineSize = p(CacheBlockBytes)
|
||||
val mem = Module(new SimDRAM(memSize, lineSize, edge.bundle)).suggestName("simdram")
|
||||
val clockFreq = p(MemoryBusKey).dtsFrequency.get
|
||||
val mem = Module(new SimDRAM(memSize, lineSize, clockFreq, edge.bundle)).suggestName("simdram")
|
||||
mem.io.axi <> port.bits
|
||||
// Bug in Chisel implementation. See https://github.com/chipsalliance/chisel3/pull/1781
|
||||
def Decoupled[T <: Data](irr: IrrevocableIO[T]): DecoupledIO[T] = {
|
||||
require(DataMirror.directionOf(irr.bits) == Direction.Output, "Only safe to cast produced Irrevocable bits to Decoupled.")
|
||||
val d = Wire(new DecoupledIO(chiselTypeOf(irr.bits)))
|
||||
d.bits := irr.bits
|
||||
d.valid := irr.valid
|
||||
irr.ready := d.ready
|
||||
d
|
||||
}
|
||||
if (additionalLatency > 0) {
|
||||
withClockAndReset (port.clock, port.reset) {
|
||||
mem.io.axi.aw <> (0 until additionalLatency).foldLeft(Decoupled(port.bits.aw))((t, _) => Queue(t, 1, pipe=true))
|
||||
mem.io.axi.w <> (0 until additionalLatency).foldLeft(Decoupled(port.bits.w ))((t, _) => Queue(t, 1, pipe=true))
|
||||
port.bits.b <> (0 until additionalLatency).foldLeft(Decoupled(mem.io.axi.b))((t, _) => Queue(t, 1, pipe=true))
|
||||
mem.io.axi.ar <> (0 until additionalLatency).foldLeft(Decoupled(port.bits.ar))((t, _) => Queue(t, 1, pipe=true))
|
||||
port.bits.r <> (0 until additionalLatency).foldLeft(Decoupled(mem.io.axi.r))((t, _) => Queue(t, 1, pipe=true))
|
||||
}
|
||||
}
|
||||
mem.io.clock := port.clock
|
||||
mem.io.reset := port.reset
|
||||
}
|
||||
@@ -183,11 +244,17 @@ class WithSimDebug extends OverrideHarnessBinder({
|
||||
case d: ClockedDMIIO =>
|
||||
val dtm_success = WireInit(false.B)
|
||||
when (dtm_success) { th.success := true.B }
|
||||
val dtm = Module(new SimDTM).connect(th.harnessClock, th.harnessReset.asBool, d, dtm_success)
|
||||
case j: JTAGIO =>
|
||||
val dtm = Module(new SimDTM).connect(th.buildtopClock, th.buildtopReset.asBool, d, dtm_success)
|
||||
case j: JTAGChipIO =>
|
||||
val dtm_success = WireInit(false.B)
|
||||
when (dtm_success) { th.success := true.B }
|
||||
val jtag = Module(new SimJTAG(tickDelay=3)).connect(j, th.harnessClock, th.harnessReset.asBool, ~(th.harnessReset.asBool), dtm_success)
|
||||
val jtag_wire = Wire(new JTAGIO)
|
||||
jtag_wire.TDO.data := j.TDO
|
||||
jtag_wire.TDO.driven := true.B
|
||||
j.TCK := jtag_wire.TCK
|
||||
j.TMS := jtag_wire.TMS
|
||||
j.TDI := jtag_wire.TDI
|
||||
val jtag = Module(new SimJTAG(tickDelay=3)).connect(jtag_wire, th.buildtopClock, th.buildtopReset.asBool, ~(th.buildtopReset.asBool), dtm_success)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -195,11 +262,10 @@ class WithSimDebug extends OverrideHarnessBinder({
|
||||
class WithTiedOffDebug extends OverrideHarnessBinder({
|
||||
(system: HasPeripheryDebug, th: HasHarnessSignalReferences, ports: Seq[Data]) => {
|
||||
ports.map {
|
||||
case j: JTAGIO =>
|
||||
case j: JTAGChipIO =>
|
||||
j.TCK := true.B.asClock
|
||||
j.TMS := true.B
|
||||
j.TDI := true.B
|
||||
j.TRSTn.foreach { r => r := true.B }
|
||||
case d: ClockedDMIIO =>
|
||||
d.dmi.req.valid := false.B
|
||||
d.dmi.req.bits := DontCare
|
||||
@@ -221,8 +287,11 @@ class WithSerialAdapterTiedOff extends OverrideHarnessBinder({
|
||||
(system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => {
|
||||
implicit val p = chipyard.iobinders.GetSystemParameters(system)
|
||||
ports.map({ port =>
|
||||
val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, port, th.harnessReset)
|
||||
SerialAdapter.tieoff(ram.module.io.tsi_ser)
|
||||
val bits = SerialAdapter.asyncQueue(port, th.buildtopClock, th.buildtopReset)
|
||||
withClockAndReset(th.buildtopClock, th.buildtopReset) {
|
||||
val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, bits, th.buildtopReset)
|
||||
SerialAdapter.tieoff(ram.module.io.tsi_ser)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -231,9 +300,12 @@ class WithSimSerial extends OverrideHarnessBinder({
|
||||
(system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => {
|
||||
implicit val p = chipyard.iobinders.GetSystemParameters(system)
|
||||
ports.map({ port =>
|
||||
val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, port, th.harnessReset)
|
||||
val success = SerialAdapter.connectSimSerial(ram.module.io.tsi_ser, port.clock, th.harnessReset.asBool)
|
||||
when (success) { th.success := true.B }
|
||||
val bits = SerialAdapter.asyncQueue(port, th.buildtopClock, th.buildtopReset)
|
||||
withClockAndReset(th.buildtopClock, th.buildtopReset) {
|
||||
val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, bits, th.buildtopReset)
|
||||
val success = SerialAdapter.connectSimSerial(ram.module.io.tsi_ser, th.buildtopClock, th.buildtopReset.asBool)
|
||||
when (success) { th.success := true.B }
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -249,3 +321,9 @@ class WithSimDromajoBridge extends ComposeHarnessBinder({
|
||||
ports.map { p => p.traces.map(tileTrace => SimDromajoBridge(tileTrace)(system.p)) }
|
||||
}
|
||||
})
|
||||
|
||||
class WithTieOffCustomBootPin extends OverrideHarnessBinder({
|
||||
(system: CanHavePeripheryCustomBootPin, th: HasHarnessSignalReferences, ports: Seq[Bool]) => {
|
||||
ports.foreach(_ := false.B)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -199,6 +199,13 @@ class WithExtInterruptIOCells extends OverrideIOBinder({
|
||||
}
|
||||
})
|
||||
|
||||
// Rocketchip's JTAGIO exposes the oe signal, which doesn't go off-chip
|
||||
class JTAGChipIO extends Bundle {
|
||||
val TCK = Input(Clock())
|
||||
val TMS = Input(Bool())
|
||||
val TDI = Input(Bool())
|
||||
val TDO = Output(Bool())
|
||||
}
|
||||
|
||||
class WithDebugIOCells extends OverrideLazyIOBinder({
|
||||
(system: HasPeripheryDebug) => {
|
||||
@@ -238,7 +245,12 @@ class WithDebugIOCells extends OverrideLazyIOBinder({
|
||||
}
|
||||
|
||||
val jtagTuple = debug.systemjtag.map { j =>
|
||||
IOCell.generateIOFromSignal(j.jtag, "jtag", p(IOCellKey), abstractResetAsAsync = true)
|
||||
val jtag_wire = Wire(new JTAGChipIO)
|
||||
j.jtag.TCK := jtag_wire.TCK
|
||||
j.jtag.TMS := jtag_wire.TMS
|
||||
j.jtag.TDI := jtag_wire.TDI
|
||||
jtag_wire.TDO := j.jtag.TDO.data
|
||||
IOCell.generateIOFromSignal(jtag_wire, "jtag", p(IOCellKey), abstractResetAsAsync = true)
|
||||
}
|
||||
|
||||
val apbTuple = debug.apb.map { a =>
|
||||
@@ -260,7 +272,6 @@ class WithSerialTLIOCells extends OverrideIOBinder({
|
||||
}).getOrElse((Nil, Nil))
|
||||
})
|
||||
|
||||
|
||||
class WithAXI4MemPunchthrough extends OverrideLazyIOBinder({
|
||||
(system: CanHaveMasterAXI4MemPort) => {
|
||||
implicit val p: Parameters = GetSystemParameters(system)
|
||||
@@ -361,6 +372,13 @@ class WithTraceIOPunchthrough extends OverrideIOBinder({
|
||||
}
|
||||
})
|
||||
|
||||
class WithCustomBootPin extends OverrideIOBinder({
|
||||
(system: CanHavePeripheryCustomBootPin) => system.custom_boot_pin.map({ p =>
|
||||
val sys = system.asInstanceOf[BaseSubsystem]
|
||||
val (port, cells) = IOCell.generateIOFromSignal(p.getWrappedValue, "custom_boot", sys.p(IOCellKey), abstractResetAsAsync = true)
|
||||
(Seq(port), cells)
|
||||
}).getOrElse((Nil, Nil))
|
||||
})
|
||||
|
||||
class WithDontTouchPorts extends OverrideIOBinder({
|
||||
(system: DontTouch) => system.dontTouchPorts(); (Nil, Nil)
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
package chipyard
|
||||
|
||||
import chisel3._
|
||||
import scala.collection.mutable.{ArrayBuffer}
|
||||
|
||||
import scala.collection.mutable.{ArrayBuffer, LinkedHashMap}
|
||||
import freechips.rocketchip.diplomacy.{LazyModule}
|
||||
import freechips.rocketchip.config.{Field, Parameters}
|
||||
import freechips.rocketchip.util.{ResetCatchAndSync}
|
||||
import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters, ClockSinkParameters, ClockParameters}
|
||||
|
||||
import chipyard.harness.{ApplyHarnessBinders, HarnessBinders}
|
||||
import chipyard.iobinders.HasIOBinders
|
||||
import chipyard.clocking.{SimplePllConfiguration, ClockDividerN}
|
||||
|
||||
// -------------------------------
|
||||
// Chipyard Test Harness
|
||||
@@ -19,26 +23,84 @@ trait HasTestHarnessFunctions {
|
||||
}
|
||||
|
||||
trait HasHarnessSignalReferences {
|
||||
def harnessClock: Clock
|
||||
def harnessReset: Reset
|
||||
// clock/reset of the chiptop reference clock (can be different than the implicit harness clock/reset)
|
||||
def buildtopClock: Clock
|
||||
def buildtopReset: Reset
|
||||
def dutReset: Reset
|
||||
def success: Bool
|
||||
}
|
||||
|
||||
class HarnessClockInstantiator {
|
||||
private val _clockMap: LinkedHashMap[String, (Double, ClockBundle)] = LinkedHashMap.empty
|
||||
|
||||
// request a clock bundle at a particular frequency
|
||||
def requestClockBundle(name: String, freqRequested: Double): ClockBundle = {
|
||||
val clockBundle = Wire(new ClockBundle(ClockBundleParameters()))
|
||||
_clockMap(name) = (freqRequested, clockBundle)
|
||||
clockBundle
|
||||
}
|
||||
|
||||
// connect all clock wires specified to a divider only PLL
|
||||
def instantiateHarnessDividerPLL(refClock: ClockBundle): Unit = {
|
||||
val sinks = _clockMap.map({ case (name, (freq, bundle)) =>
|
||||
ClockSinkParameters(take=Some(ClockParameters(freqMHz=freq / (1000 * 1000))), name=Some(name))
|
||||
}).toSeq
|
||||
|
||||
val pllConfig = new SimplePllConfiguration("harnessDividerOnlyClockGenerator", sinks)
|
||||
pllConfig.emitSummaries()
|
||||
|
||||
val dividedClocks = LinkedHashMap[Int, Clock]()
|
||||
def instantiateDivider(div: Int): Clock = {
|
||||
val divider = Module(new ClockDividerN(div))
|
||||
divider.suggestName(s"ClockDivideBy${div}")
|
||||
divider.io.clk_in := refClock.clock
|
||||
dividedClocks(div) = divider.io.clk_out
|
||||
divider.io.clk_out
|
||||
}
|
||||
|
||||
// connect wires to clock source
|
||||
for (sinkParams <- sinks) {
|
||||
// bypass the reference freq. (don't create a divider + reset sync)
|
||||
val (divClock, divReset) = if (sinkParams.take.get.freqMHz != pllConfig.referenceFreqMHz) {
|
||||
val div = pllConfig.sinkDividerMap(sinkParams)
|
||||
val divClock = dividedClocks.getOrElse(div, instantiateDivider(div))
|
||||
(divClock, ResetCatchAndSync(divClock, refClock.reset.asBool))
|
||||
} else {
|
||||
(refClock.clock, refClock.reset)
|
||||
}
|
||||
|
||||
_clockMap(sinkParams.name.get)._2.clock := divClock
|
||||
_clockMap(sinkParams.name.get)._2.reset := divReset
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case object HarnessClockInstantiatorKey extends Field[HarnessClockInstantiator](new HarnessClockInstantiator)
|
||||
|
||||
class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSignalReferences {
|
||||
val io = IO(new Bundle {
|
||||
val success = Output(Bool())
|
||||
})
|
||||
|
||||
val buildtopClock = Wire(Clock())
|
||||
val buildtopReset = Wire(Reset())
|
||||
|
||||
val lazyDut = LazyModule(p(BuildTop)(p)).suggestName("chiptop")
|
||||
val dut = Module(lazyDut.module)
|
||||
|
||||
io.success := false.B
|
||||
|
||||
val harnessClock = clock
|
||||
val harnessReset = WireInit(reset)
|
||||
val success = io.success
|
||||
val freqMHz = lazyDut match {
|
||||
case d: HasReferenceClockFreq => d.refClockFreqMHz
|
||||
case _ => p(DefaultClockFrequencyKey)
|
||||
}
|
||||
val refClkBundle = p(HarnessClockInstantiatorKey).requestClockBundle("buildtop_reference_clock", freqMHz * (1000 * 1000))
|
||||
|
||||
val dutReset = reset.asAsyncReset
|
||||
buildtopClock := refClkBundle.clock
|
||||
buildtopReset := WireInit(refClkBundle.reset)
|
||||
val dutReset = refClkBundle.reset.asAsyncReset
|
||||
|
||||
val success = io.success
|
||||
|
||||
lazyDut match { case d: HasTestHarnessFunctions =>
|
||||
d.harnessFunctions.foreach(_(this))
|
||||
@@ -46,5 +108,10 @@ class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSign
|
||||
lazyDut match { case d: HasIOBinders =>
|
||||
ApplyHarnessBinders(this, d.lazySystem, d.portMap)
|
||||
}
|
||||
|
||||
val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters()))
|
||||
implicitHarnessClockBundle.clock := clock
|
||||
implicitHarnessClockBundle.reset := reset
|
||||
p(HarnessClockInstantiatorKey).instantiateHarnessDividerPLL(implicitHarnessClockBundle)
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ object FrequencyUtils {
|
||||
require(!requestedOutputs.contains(0.0))
|
||||
val requestedFreqs = requestedOutputs.map(_.freqMHz)
|
||||
val fastestFreq = requestedFreqs.max
|
||||
require(fastestFreq < maximumAllowableFreqMHz)
|
||||
require(fastestFreq <= maximumAllowableFreqMHz)
|
||||
|
||||
val candidateFreqs =
|
||||
Seq.tabulate(Math.ceil(maximumAllowableFreqMHz / fastestFreq).toInt)(i => (i + 1) * fastestFreq)
|
||||
@@ -89,6 +89,7 @@ class SimplePllConfiguration(
|
||||
ElaborationArtefacts.add(s"${name}.freq-summary", summaryString)
|
||||
println(summaryString)
|
||||
}
|
||||
def referenceSinkParams(): ClockSinkParameters = sinkDividerMap.find(_._2 == 1).get._1
|
||||
}
|
||||
|
||||
case class DividerOnlyClockGeneratorNode(pllName: String)(implicit valName: ValName)
|
||||
@@ -144,7 +145,3 @@ class DividerOnlyClockGenerator(pllName: String)(implicit p: Parameters, valName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object DividerOnlyClockGenerator {
|
||||
def apply()(implicit p: Parameters, valName: ValName) = LazyModule(new DividerOnlyClockGenerator(valName.name)).node
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ class AbstractConfig extends Config(
|
||||
new chipyard.harness.WithSimAXIMMIO ++ // add SimAXIMem for axi4 mmio port, if enabled
|
||||
new chipyard.harness.WithTieOffInterrupts ++ // tie-off interrupt ports, if present
|
||||
new chipyard.harness.WithTieOffL2FBusAXI ++ // tie-off external AXI4 master, if present
|
||||
new chipyard.harness.WithTieOffCustomBootPin ++
|
||||
|
||||
// The IOBinders instantiate ChipTop IOs to match desired digital IOs
|
||||
// IOCells are generated for "Chip-like" IOs, while simulation-only IOs are directly punched through
|
||||
@@ -37,6 +38,7 @@ class AbstractConfig extends Config(
|
||||
new chipyard.iobinders.WithSPIIOCells ++
|
||||
new chipyard.iobinders.WithTraceIOPunchthrough ++
|
||||
new chipyard.iobinders.WithExtInterruptIOCells ++
|
||||
new chipyard.iobinders.WithCustomBootPin ++
|
||||
|
||||
new testchipip.WithDefaultSerialTL ++ // use serialized tilelink port to external serialadapter/harnessRAM
|
||||
new chipyard.config.WithBootROM ++ // use default bootrom
|
||||
@@ -45,6 +47,8 @@ class AbstractConfig extends Config(
|
||||
new chipyard.config.WithNoSubsystemDrivenClocks ++ // drive the subsystem diplomatic clocks from ChipTop instead of using implicit clocks
|
||||
new chipyard.config.WithInheritBusFrequencyAssignments ++ // Unspecified clocks within a bus will receive the bus frequency if set
|
||||
new chipyard.config.WithPeripheryBusFrequencyAsDefault ++ // Unspecified frequencies with match the pbus frequency (which is always set)
|
||||
new chipyard.config.WithMemoryBusFrequency(100.0) ++ // Default 100 MHz mbus
|
||||
new chipyard.config.WithPeripheryBusFrequency(100.0) ++ // Default 100 MHz pbus
|
||||
new freechips.rocketchip.subsystem.WithJtagDTM ++ // set the debug module to expose a JTAG port
|
||||
new freechips.rocketchip.subsystem.WithNoMMIOPort ++ // no top-level MMIO master port (overrides default set in rocketchip)
|
||||
new freechips.rocketchip.subsystem.WithNoSlavePort ++ // no top-level MMIO slave port (overrides default set in rocketchip)
|
||||
@@ -52,4 +56,3 @@ class AbstractConfig extends Config(
|
||||
new freechips.rocketchip.subsystem.WithNExtTopInterrupts(0) ++ // no external interrupts
|
||||
new chipyard.WithMulticlockCoherentBusTopology ++ // hierarchical buses including mbus+l2
|
||||
new freechips.rocketchip.system.BaseConfig) // "base" rocketchip system
|
||||
|
||||
|
||||
@@ -20,23 +20,35 @@ class HwachaLargeBoomAndHwachaRocketConfig extends Config(
|
||||
new chipyard.config.AbstractConfig)
|
||||
// DOC include end: BoomAndRocketWithHwacha
|
||||
|
||||
// DOC include start: DualBoomAndRocketOneHwacha
|
||||
class LargeBoomAndHwachaRocketConfig extends Config(
|
||||
new chipyard.config.WithMultiRoCC ++ // support heterogeneous rocc
|
||||
new chipyard.config.WithMultiRoCCHwacha(1) ++ // put hwacha on hart-1 (rocket)
|
||||
new chipyard.config.WithMultiRoCCHwacha(0) ++ // put hwacha on hart-0 (rocket)
|
||||
new hwacha.DefaultHwachaConfig ++ // set default hwacha config keys
|
||||
new boom.common.WithNLargeBooms(1) ++ // add 1 boom core
|
||||
new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // add 1 rocket core
|
||||
new chipyard.config.AbstractConfig)
|
||||
|
||||
// DOC include start: DualBoomAndRocketOneHwacha
|
||||
class DualLargeBoomAndHwachaRocketConfig extends Config(
|
||||
new chipyard.config.WithMultiRoCC ++ // support heterogeneous rocc
|
||||
new chipyard.config.WithMultiRoCCHwacha(0) ++ // put hwacha on hart-0 (rocket)
|
||||
new hwacha.DefaultHwachaConfig ++ // set default hwacha config keys
|
||||
new boom.common.WithNLargeBooms(2) ++ // add 2 boom cores
|
||||
new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // add 1 rocket core
|
||||
new chipyard.config.AbstractConfig)
|
||||
// DOC include end: DualBoomAndRocketOneHwacha
|
||||
|
||||
|
||||
// DOC include start: DualBoomAndRocket
|
||||
class DualLargeBoomAndDualRocketConfig extends Config(
|
||||
new boom.common.WithNLargeBooms(2) ++ // add 2 boom cores
|
||||
new freechips.rocketchip.subsystem.WithNBigCores(2) ++ // add 2 rocket cores
|
||||
new chipyard.config.AbstractConfig)
|
||||
// DOC include end: DualBoomAndRocket
|
||||
|
||||
// DOC include start: DualBoomAndSingleRocket
|
||||
class DualLargeBoomAndSingleRocketConfig extends Config(
|
||||
new boom.common.WithNLargeBooms(2) ++ // add 2 boom cores
|
||||
new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // add 1 rocket core
|
||||
new chipyard.config.AbstractConfig)
|
||||
// DOC include end: DualBoomAndSingleRocket
|
||||
|
||||
class LargeBoomAndRocketWithControlCoreConfig extends Config(
|
||||
new freechips.rocketchip.subsystem.WithNSmallCores(1) ++ // Add a small "control" core
|
||||
|
||||
@@ -34,6 +34,12 @@ class GemminiRocketConfig extends Config(
|
||||
new chipyard.config.AbstractConfig)
|
||||
// DOC include end: GemminiRocketConfig
|
||||
|
||||
class FPGemminiRocketConfig extends Config(
|
||||
new gemmini.GemminiFP32DefaultConfig ++ // use FP32Gemmini systolic array GEMM accelerator
|
||||
new freechips.rocketchip.subsystem.WithNBigCores(1) ++
|
||||
new chipyard.config.AbstractConfig)
|
||||
|
||||
|
||||
// DOC include start: DmiRocket
|
||||
class dmiRocketConfig extends Config(
|
||||
new chipyard.harness.WithSerialAdapterTiedOff ++ // don't attach an external SimSerial
|
||||
@@ -206,3 +212,26 @@ class LBWIFRocketConfig extends Config(
|
||||
new freechips.rocketchip.subsystem.WithNoMemPort ++ // remove AXI4 backing memory
|
||||
new freechips.rocketchip.subsystem.WithNBigCores(1) ++
|
||||
new chipyard.config.AbstractConfig)
|
||||
|
||||
// DOC include start: MulticlockAXIOverSerialConfig
|
||||
class MulticlockAXIOverSerialConfig extends Config(
|
||||
new chipyard.config.WithSystemBusFrequencyAsDefault ++
|
||||
new chipyard.config.WithSystemBusFrequency(250) ++
|
||||
new chipyard.config.WithPeripheryBusFrequency(250) ++
|
||||
new chipyard.config.WithMemoryBusFrequency(250) ++
|
||||
new chipyard.config.WithFrontBusFrequency(50) ++
|
||||
new chipyard.config.WithTileFrequency(500, Some(1)) ++
|
||||
new chipyard.config.WithTileFrequency(250, Some(0)) ++
|
||||
|
||||
new chipyard.config.WithFbusToSbusCrossingType(AsynchronousCrossing()) ++
|
||||
new testchipip.WithAsynchronousSerialSlaveCrossing ++
|
||||
new freechips.rocketchip.subsystem.WithAsynchronousRocketTiles(
|
||||
AsynchronousCrossing().depth,
|
||||
AsynchronousCrossing().sourceSync) ++
|
||||
|
||||
new chipyard.harness.WithSimAXIMemOverSerialTL ++ // add SimDRAM DRAM model for axi4 backing memory over the SerDes link, if axi4 mem is enabled
|
||||
new chipyard.config.WithSerialTLBackingMemory ++ // remove axi4 mem port in favor of SerialTL memory
|
||||
|
||||
new freechips.rocketchip.subsystem.WithNBigCores(2) ++
|
||||
new chipyard.config.AbstractConfig)
|
||||
// DOC include end: MulticlockAXIOverSerialConfig
|
||||
|
||||
@@ -11,6 +11,8 @@ class AbstractTraceGenConfig extends Config(
|
||||
new chipyard.config.WithTracegenSystem ++
|
||||
new chipyard.config.WithNoSubsystemDrivenClocks ++
|
||||
new chipyard.config.WithPeripheryBusFrequencyAsDefault ++
|
||||
new chipyard.config.WithMemoryBusFrequency(100.0) ++
|
||||
new chipyard.config.WithPeripheryBusFrequency(100.0) ++
|
||||
new freechips.rocketchip.subsystem.WithCoherentBusTopology ++
|
||||
new freechips.rocketchip.groundtest.GroundTestBaseConfig)
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ import freechips.rocketchip.devices.debug.{Debug, HasPeripheryDebugModuleImp}
|
||||
import freechips.rocketchip.amba.axi4.{AXI4Bundle}
|
||||
import freechips.rocketchip.subsystem._
|
||||
import freechips.rocketchip.tile.{RocketTile}
|
||||
import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters}
|
||||
import freechips.rocketchip.util.{ResetCatchAndSync}
|
||||
import sifive.blocks.devices.uart._
|
||||
|
||||
import testchipip._
|
||||
@@ -70,8 +72,11 @@ class WithSerialBridge extends OverrideHarnessBinder({
|
||||
(system: CanHavePeripheryTLSerial, th: FireSim, ports: Seq[ClockedIO[SerialIO]]) => {
|
||||
ports.map { port =>
|
||||
implicit val p = GetSystemParameters(system)
|
||||
val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, port, th.harnessReset)
|
||||
SerialBridge(port.clock, ram.module.io.tsi_ser, p(ExtMem).map(_ => MainMemoryConsts.globalName))
|
||||
val bits = SerialAdapter.asyncQueue(port, th.buildtopClock, th.buildtopReset)
|
||||
val ram = withClockAndReset(th.buildtopClock, th.buildtopReset) {
|
||||
SerialAdapter.connectHarnessRAM(system.serdesser.get, bits, th.buildtopReset)
|
||||
}
|
||||
SerialBridge(th.buildtopClock, ram.module.io.tsi_ser, p(ExtMem).map(_ => MainMemoryConsts.globalName))
|
||||
}
|
||||
Nil
|
||||
}
|
||||
@@ -98,7 +103,56 @@ class WithUARTBridge extends OverrideHarnessBinder({
|
||||
class WithBlockDeviceBridge extends OverrideHarnessBinder({
|
||||
(system: CanHavePeripheryBlockDevice, th: FireSim, ports: Seq[ClockedIO[BlockDeviceIO]]) => {
|
||||
implicit val p: Parameters = GetSystemParameters(system)
|
||||
ports.map { b => BlockDevBridge(b.clock, b.bits, th.harnessReset.toBool) }
|
||||
ports.map { b => BlockDevBridge(b.clock, b.bits, th.buildtopReset.asBool) }
|
||||
Nil
|
||||
}
|
||||
})
|
||||
|
||||
class WithAXIOverSerialTLCombinedBridges extends OverrideHarnessBinder({
|
||||
(system: CanHavePeripheryTLSerial, th: FireSim, ports: Seq[ClockedIO[SerialIO]]) => {
|
||||
implicit val p = GetSystemParameters(system)
|
||||
|
||||
p(SerialTLKey).map({ sVal =>
|
||||
require(sVal.axiMemOverSerialTLParams.isDefined)
|
||||
val axiDomainParams = sVal.axiMemOverSerialTLParams.get
|
||||
require(sVal.isMemoryDevice)
|
||||
|
||||
val memFreq = axiDomainParams.getMemFrequency(system.asInstanceOf[HasTileLinkLocations])
|
||||
|
||||
ports.map({ port =>
|
||||
val axiClock = p(ClockBridgeInstantiatorKey).requestClock("mem_over_serial_tl_clock", memFreq)
|
||||
val axiClockBundle = Wire(new ClockBundle(ClockBundleParameters()))
|
||||
axiClockBundle.clock := axiClock
|
||||
axiClockBundle.reset := ResetCatchAndSync(axiClock, th.buildtopReset.asBool)
|
||||
|
||||
val serial_bits = SerialAdapter.asyncQueue(port, th.buildtopClock, th.buildtopReset)
|
||||
|
||||
val harnessMultiClockAXIRAM = withClockAndReset(th.buildtopClock, th.buildtopReset) {
|
||||
SerialAdapter.connectHarnessMultiClockAXIRAM(
|
||||
system.serdesser.get,
|
||||
serial_bits,
|
||||
axiClockBundle,
|
||||
th.buildtopReset)
|
||||
}
|
||||
SerialBridge(th.buildtopClock, harnessMultiClockAXIRAM.module.io.tsi_ser, Some(MainMemoryConsts.globalName))
|
||||
|
||||
// connect SimAxiMem
|
||||
(harnessMultiClockAXIRAM.mem_axi4 zip harnessMultiClockAXIRAM.memNode.edges.in).map { case (axi4, edge) =>
|
||||
val nastiKey = NastiParameters(axi4.bits.r.bits.data.getWidth,
|
||||
axi4.bits.ar.bits.addr.getWidth,
|
||||
axi4.bits.ar.bits.id.getWidth)
|
||||
system match {
|
||||
case s: BaseSubsystem => FASEDBridge(axi4.clock, axi4.bits, axi4.reset.asBool,
|
||||
CompleteConfig(p(firesim.configs.MemModelKey),
|
||||
nastiKey,
|
||||
Some(AXI4EdgeSummary(edge)),
|
||||
Some(MainMemoryConsts.globalName)))
|
||||
case _ => throw new Exception("Attempting to attach FASED Bridge to misconfigured design")
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Nil
|
||||
}
|
||||
})
|
||||
@@ -138,7 +192,7 @@ class WithDromajoBridge extends ComposeHarnessBinder({
|
||||
|
||||
class WithTraceGenBridge extends OverrideHarnessBinder({
|
||||
(system: TraceGenSystemModuleImp, th: FireSim, ports: Seq[Bool]) =>
|
||||
ports.map { p => GroundTestBridge(th.harnessClock, p)(system.p) }; Nil
|
||||
ports.map { p => GroundTestBridge(th.buildtopClock, p)(system.p) }; Nil
|
||||
})
|
||||
|
||||
class WithFireSimMultiCycleRegfile extends ComposeIOBinder({
|
||||
@@ -170,6 +224,7 @@ class WithFireSimFAME5 extends ComposeIOBinder({
|
||||
annotate(EnableModelMultiThreadingAnnotation(b.module))
|
||||
case r: RocketTile =>
|
||||
annotate(EnableModelMultiThreadingAnnotation(r.module))
|
||||
case _ => Nil
|
||||
}
|
||||
(Nil, Nil)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
package firesim.firesim
|
||||
|
||||
import scala.collection.mutable.{LinkedHashMap}
|
||||
|
||||
import chisel3._
|
||||
import chisel3.experimental.{IO}
|
||||
|
||||
@@ -38,44 +40,113 @@ object NodeIdx {
|
||||
/**
|
||||
* Under FireSim's current multiclock implementation there can be only a
|
||||
* single clock bridge. This requires, therefore, that it be instantiated in
|
||||
* the harness and reused across all supernode instances. This class attempts to
|
||||
* the harness and reused across all supernode instances. This class attempts to
|
||||
* memoize its instantiation such that it can be referenced from within a ClockScheme function.
|
||||
*/
|
||||
class ClockBridgeInstantiator {
|
||||
private var _clockRecord: Option[RecordMap[Clock]] = None
|
||||
private val _harnessClockMap: LinkedHashMap[String, (Double, Clock)] = LinkedHashMap.empty
|
||||
|
||||
def getClockRecord: RecordMap[Clock] = _clockRecord.get
|
||||
// Assumes that the supernode implementation results in duplicated clocks
|
||||
// (i.e. only 1 set of clocks is generated for all BuildTop designs)
|
||||
private val _buildtopClockMap: LinkedHashMap[String, (RationalClock, Clock)] = LinkedHashMap.empty
|
||||
private var _buildtopRefTuple: Option[(String, Double)] = None
|
||||
|
||||
def getClockRecordOrInstantiate(allClocks: Seq[RationalClock], baseClockName: String): RecordMap[Clock] = {
|
||||
if (_clockRecord.isEmpty) {
|
||||
require(allClocks.exists(_.name == baseClockName),
|
||||
s"Provided base-clock name, ${baseClockName}, does not match a defined clock. Available clocks:\n " +
|
||||
allClocks.map(_.name).mkString("\n "))
|
||||
/**
|
||||
* Request a clock at a particular frequency
|
||||
*
|
||||
* @param name An identifier for the associated clock domain
|
||||
*
|
||||
* @param freqRequested Freq. for the domain in Hz
|
||||
*/
|
||||
def requestClock(name: String, freqRequested: Double): Clock = {
|
||||
val clkWire = Wire(new Clock)
|
||||
_harnessClockMap(name) = (freqRequested, clkWire)
|
||||
clkWire
|
||||
}
|
||||
|
||||
val baseClock = allClocks.find(_.name == baseClockName).get
|
||||
val simplified = allClocks.map { c =>
|
||||
c.copy(multiplier = c.multiplier * baseClock.divisor, divisor = c.divisor * baseClock.multiplier)
|
||||
.simplify
|
||||
}
|
||||
/**
|
||||
* Get a RecordMap of clocks for a set of input RationalClocks
|
||||
*
|
||||
* @param allClocks Seq. of RationalClocks that want a clock
|
||||
*
|
||||
* @param baseClockName Name of domain that the allClocks is rational to
|
||||
*
|
||||
* @param baseFreqRequested Freq. for the reference domain in Hz
|
||||
*/
|
||||
def requestClockRecordMap(allClocks: Seq[RationalClock], baseClockName: String, baseFreqRequested: Double): RecordMap[Clock] = {
|
||||
require(!_buildtopRefTuple.isDefined, "Can only request one RecordMap of Clocks")
|
||||
|
||||
/**
|
||||
* Removes clocks that have the same frequency before instantiating the
|
||||
* clock bridge to avoid unnecessary BUFGCE use.
|
||||
*/
|
||||
val distinct = simplified.foldLeft(Seq(RationalClock(baseClockName, 1, 1))) { case (list, candidate) =>
|
||||
if (list.exists { clock => clock.equalFrequency(candidate) }) list else list :+ candidate
|
||||
}
|
||||
val ratClockRecordMapWire = Wire(RecordMap(allClocks.map { c => (c.name, Clock()) }:_*))
|
||||
|
||||
val clockBridge = Module(new RationalClockBridge(distinct))
|
||||
val cbVecTuples = distinct.zip(clockBridge.io.clocks)
|
||||
val outputWire = Wire(RecordMap(simplified.map { c => (c.name, Clock()) }:_*))
|
||||
for (parameter <- simplified) {
|
||||
val (_, cbClockField) = cbVecTuples.find(_._1.equalFrequency(parameter)).get
|
||||
outputWire(parameter.name).get := cbClockField
|
||||
}
|
||||
_clockRecord = Some(outputWire)
|
||||
_buildtopRefTuple = Some((baseClockName, baseFreqRequested))
|
||||
for (clock <- allClocks) {
|
||||
val clkWire = Wire(new Clock)
|
||||
_buildtopClockMap(clock.name) = (clock, clkWire)
|
||||
ratClockRecordMapWire(clock.name).get := clkWire
|
||||
}
|
||||
|
||||
ratClockRecordMapWire
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect all clocks requested to ClockBridge
|
||||
*/
|
||||
def instantiateFireSimClockBridge: Unit = {
|
||||
require(_buildtopRefTuple.isDefined, "Must have rational clocks to assign to")
|
||||
require(_buildtopClockMap.exists(_._1 == _buildtopRefTuple.get._1),
|
||||
s"Provided base-clock name for rational clocks, ${_buildtopRefTuple.get._1}, doesn't match a name within specified rational clocks." +
|
||||
"Available clocks:\n " + _buildtopClockMap.map(_._1).mkString("\n "))
|
||||
|
||||
// Simplify the RationalClocks ratio's
|
||||
val refRatClock = _buildtopClockMap.find(_._1 == _buildtopRefTuple.get._1).get._2._1
|
||||
val simpleRatClocks = _buildtopClockMap.map { t =>
|
||||
val ratClock = t._2._1
|
||||
ratClock.copy(
|
||||
multiplier = ratClock.multiplier * refRatClock.divisor,
|
||||
divisor = ratClock.divisor * refRatClock.multiplier).simplify
|
||||
}
|
||||
|
||||
// Determine all the clock dividers (harness + rational clocks)
|
||||
// Note: Requires that the BuildTop reference frequency is requested with proper freq.
|
||||
val refRatClockFreq = _buildtopRefTuple.get._2
|
||||
val refRatSinkParams = ClockSinkParameters(take=Some(ClockParameters(freqMHz=refRatClockFreq / (1000 * 1000))),name=Some(_buildtopRefTuple.get._1))
|
||||
val harSinkParams = _harnessClockMap.map { case (name, (freq, bundle)) =>
|
||||
ClockSinkParameters(take=Some(ClockParameters(freqMHz=freq / (1000 * 1000))),name=Some(name))
|
||||
}.toSeq
|
||||
val allSinkParams = harSinkParams :+ refRatSinkParams
|
||||
|
||||
// Use PLL config to determine overall div's
|
||||
val pllConfig = new SimplePllConfiguration("firesimOverallClockBridge", allSinkParams)
|
||||
pllConfig.emitSummaries
|
||||
|
||||
// Adjust all BuildTop RationalClocks with the div determined by the PLL
|
||||
val refRatDiv = pllConfig.sinkDividerMap(refRatSinkParams)
|
||||
val adjRefRatClocks = simpleRatClocks.map { clock =>
|
||||
clock.copy(divisor = clock.divisor * refRatDiv).simplify
|
||||
}
|
||||
|
||||
// Convert harness clocks to RationalClocks
|
||||
val harRatClocks = harSinkParams.map { case ClockSinkParameters(_, _, _, _, clkParamsOpt, nameOpt) =>
|
||||
RationalClock(nameOpt.get, 1, pllConfig.referenceFreqMHz.toInt / clkParamsOpt.get.freqMHz.toInt)
|
||||
}
|
||||
|
||||
val allAdjRatClks = adjRefRatClocks ++ harRatClocks
|
||||
|
||||
// Removes clocks that have the same frequency before instantiating the
|
||||
// clock bridge to avoid unnecessary BUFGCE use.
|
||||
val allDistinctRatClocks = allAdjRatClks.foldLeft(Seq(RationalClock(pllConfig.referenceSinkParams.name.get, 1, 1))) {
|
||||
case (list, candidate) => if (list.exists { clock => clock.equalFrequency(candidate) }) list else list :+ candidate
|
||||
}
|
||||
|
||||
val clockBridge = Module(new RationalClockBridge(allDistinctRatClocks))
|
||||
val cbVecTuples = allDistinctRatClocks.zip(clockBridge.io.clocks)
|
||||
|
||||
// Connect all clocks (harness + BuildTop clocks)
|
||||
for (clock <- allAdjRatClks) {
|
||||
val (_, cbClockField) = cbVecTuples.find(_._1.equalFrequency(clock)).get
|
||||
_buildtopClockMap.get(clock.name).map { case (_, clk) => clk := cbClockField }
|
||||
_harnessClockMap.get(clock.name).map { case (_, clk) => clk := cbClockField }
|
||||
}
|
||||
getClockRecord
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,29 +188,35 @@ class WithFireSimSimpleClocks extends Config((site, here, up) => {
|
||||
clockBundle.reset := reset
|
||||
}
|
||||
|
||||
val pllConfig = new SimplePllConfiguration("FireSim RationalClockBridge", clockGroupEdge.sink.members)
|
||||
val pllConfig = new SimplePllConfiguration("firesimBuildTopClockGenerator", clockGroupEdge.sink.members)
|
||||
pllConfig.emitSummaries
|
||||
val rationalClockSpecs = for ((sinkP, division) <- pllConfig.sinkDividerMap) yield {
|
||||
RationalClock(sinkP.name.get, 1, division)
|
||||
}
|
||||
|
||||
chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => {
|
||||
reset := th.harnessReset
|
||||
reset := th.buildtopReset
|
||||
input_clocks := p(ClockBridgeInstantiatorKey)
|
||||
.getClockRecordOrInstantiate(rationalClockSpecs.toSeq, p(FireSimBaseClockNameKey))
|
||||
.requestClockRecordMap(rationalClockSpecs.toSeq, p(FireSimBaseClockNameKey), pllConfig.referenceFreqMHz * (1000 * 1000))
|
||||
Nil })
|
||||
|
||||
// return the reference frequency
|
||||
pllConfig.referenceFreqMHz
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessSignalReferences {
|
||||
freechips.rocketchip.util.property.cover.setPropLib(new midas.passes.FireSimPropertyLibrary())
|
||||
val harnessClock = Wire(Clock())
|
||||
val harnessReset = WireInit(false.B)
|
||||
val peekPokeBridge = PeekPokeBridge(harnessClock, harnessReset)
|
||||
|
||||
val buildtopClock = Wire(Clock())
|
||||
val buildtopReset = WireInit(false.B)
|
||||
val peekPokeBridge = PeekPokeBridge(buildtopClock, buildtopReset)
|
||||
def dutReset = { require(false, "dutReset should not be used in Firesim"); false.B }
|
||||
def success = { require(false, "success should not be used in Firesim"); false.B }
|
||||
|
||||
var btFreqMHz: Option[Double] = None
|
||||
|
||||
// Instantiate multiple instances of the DUT to implement supernode
|
||||
for (i <- 0 until p(NumNodes)) {
|
||||
// It's not a RC bump without some hacks...
|
||||
@@ -151,6 +228,12 @@ class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessSigna
|
||||
case AsyncClockGroupsKey => p(AsyncClockGroupsKey).copy
|
||||
})))
|
||||
val module = Module(lazyModule.module)
|
||||
|
||||
btFreqMHz = Some(lazyModule match {
|
||||
case d: HasReferenceClockFreq => d.refClockFreqMHz
|
||||
case _ => p(DefaultClockFrequencyKey)
|
||||
})
|
||||
|
||||
lazyModule match { case d: HasTestHarnessFunctions =>
|
||||
require(d.harnessFunctions.size == 1, "There should only be 1 harness function to connect clock+reset")
|
||||
d.harnessFunctions.foreach(_(this))
|
||||
@@ -160,5 +243,8 @@ class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessSigna
|
||||
}
|
||||
NodeIdx.increment()
|
||||
}
|
||||
harnessClock := p(ClockBridgeInstantiatorKey).getClockRecord("implicit_clock").get
|
||||
|
||||
buildtopClock := p(ClockBridgeInstantiatorKey).requestClock("buildtop_reference_clock", btFreqMHz.get * (1000 * 1000))
|
||||
|
||||
p(ClockBridgeInstantiatorKey).instantiateFireSimClockBridge
|
||||
}
|
||||
|
||||
@@ -59,28 +59,14 @@ class WithNIC extends icenet.WithIceNIC(inBufFlits = 8192, ctrlQueueDepth = 64)
|
||||
class WithNVDLALarge extends nvidia.blocks.dla.WithNVDLA("large")
|
||||
class WithNVDLASmall extends nvidia.blocks.dla.WithNVDLA("small")
|
||||
|
||||
|
||||
// Tweaks that are generally applied to all firesim configs
|
||||
class WithFireSimConfigTweaks extends Config(
|
||||
// Non-frequency tweaks that are generally applied to all firesim configs
|
||||
class WithFireSimDesignTweaks extends Config(
|
||||
// Required: Bake in the default FASED memory model
|
||||
new WithDefaultMemModel ++
|
||||
// Required*: Uses FireSim ClockBridge and PeekPokeBridge to drive the system with a single clock/reset
|
||||
new WithFireSimSimpleClocks ++
|
||||
// Required*: When using FireSim-as-top to provide a correct path to the target bootrom source
|
||||
new WithBootROM ++
|
||||
// Optional: This sets the default frequency for all buses in the system to 3.2 GHz
|
||||
// (since unspecified bus frequencies will use the pbus frequency)
|
||||
// This frequency selection matches FireSim's legacy selection and is required
|
||||
// to support 200Gb NIC performance. You may select a smaller value.
|
||||
new chipyard.config.WithPeripheryBusFrequency(3200.0) ++
|
||||
// Optional: These three configs put the DRAM memory system in it's own clock domian.
|
||||
// Removing the first config will result in the FASED timing model running
|
||||
// at the pbus freq (above, 3.2 GHz), which is outside the range of valid DDR3 speedgrades.
|
||||
// 1 GHz matches the FASED default, using some other frequency will require
|
||||
// runnings the FASED runtime configuration generator to generate faithful DDR3 timing values.
|
||||
new chipyard.config.WithMemoryBusFrequency(1000.0) ++
|
||||
new chipyard.config.WithAsynchrousMemoryBusCrossing ++
|
||||
new testchipip.WithAsynchronousSerialSlaveCrossing ++
|
||||
// Required: Existing FAME-1 transform cannot handle black-box clock gates
|
||||
new WithoutClockGating ++
|
||||
// Required*: Removes thousands of assertions that would be synthesized (* pending PriorityMux bugfix)
|
||||
@@ -89,10 +75,6 @@ class WithFireSimConfigTweaks extends Config(
|
||||
new chipyard.config.WithTraceIO ++
|
||||
// Optional: Request 16 GiB of target-DRAM by default (can safely request up to 32 GiB on F1)
|
||||
new freechips.rocketchip.subsystem.WithExtMemSize((1 << 30) * 16L) ++
|
||||
// Required: Adds IO to attach SerialBridge. The SerialBridges is responsible
|
||||
// for signalling simulation termination under simulation success. This fragment can
|
||||
// be removed if you supply an auxiliary bridge that signals simulation termination
|
||||
new testchipip.WithDefaultSerialTL ++
|
||||
// Optional: Removing this will require using an initramfs under linux
|
||||
new testchipip.WithBlockDevice ++
|
||||
// Optional: Set a UART baudrate (this selection matches FireSim's historical value)
|
||||
@@ -101,6 +83,27 @@ class WithFireSimConfigTweaks extends Config(
|
||||
new chipyard.config.WithNoDebug
|
||||
)
|
||||
|
||||
// Tweaks to modify target clock frequencies / crossings to firesim defaults
|
||||
class WithFireSimDefaultFrequencyTweaks extends Config(
|
||||
// Optional*: Removing this will require adjusting the UART baud rate and
|
||||
// potential target-software changes to properly capture UART output
|
||||
new chipyard.config.WithPeripheryBusFrequency(3200.0) ++
|
||||
// Optional: These three configs put the DRAM memory system in it's own clock domian.
|
||||
// Removing the first config will result in the FASED timing model running
|
||||
// at the pbus freq (above, 3.2 GHz), which is outside the range of valid DDR3 speedgrades.
|
||||
// 1 GHz matches the FASED default, using some other frequency will require
|
||||
// runnings the FASED runtime configuration generator to generate faithful DDR3 timing values.
|
||||
new chipyard.config.WithMemoryBusFrequency(1000.0) ++
|
||||
new chipyard.config.WithAsynchrousMemoryBusCrossing ++
|
||||
new testchipip.WithAsynchronousSerialSlaveCrossing
|
||||
)
|
||||
|
||||
// Tweaks that are generally applied to all firesim configs
|
||||
class WithFireSimConfigTweaks extends Config(
|
||||
new WithFireSimDefaultFrequencyTweaks ++
|
||||
new WithFireSimDesignTweaks
|
||||
)
|
||||
|
||||
/*******************************************************************************
|
||||
* Full TARGET_CONFIG configurations. These set parameters of the target being
|
||||
* simulated.
|
||||
@@ -206,6 +209,15 @@ class FireSimMulticlockRocketConfig extends Config(
|
||||
new freechips.rocketchip.subsystem.WithRationalRocketTiles ++ // Add rational crossings between RocketTile and uncore
|
||||
new FireSimRocketConfig)
|
||||
|
||||
class FireSimMulticlockAXIOverSerialConfig extends Config(
|
||||
new WithAXIOverSerialTLCombinedBridges ++ // use combined bridge to connect to axi mem over serial
|
||||
new WithDefaultFireSimBridges ++
|
||||
new testchipip.WithBlockDevice(false) ++ // disable blockdev
|
||||
new WithDefaultMemModel ++
|
||||
new WithFireSimDesignTweaks ++ // don't inherit firesim clocking
|
||||
new chipyard.MulticlockAXIOverSerialConfig
|
||||
)
|
||||
|
||||
//**********************************************************************************
|
||||
// System with 16 LargeBOOMs that can be simulated with Golden Gate optimizations
|
||||
// - Requires MTModels and MCRams mixins as prefixes to the platform config
|
||||
@@ -217,3 +229,4 @@ class FireSim16LargeBoomConfig extends Config(
|
||||
new WithFireSimConfigTweaks ++
|
||||
new boom.common.WithNLargeBooms(16) ++
|
||||
new chipyard.config.AbstractConfig)
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ usage() {
|
||||
echo " --prefix PREFIX : Install destination. If unset, defaults to $(pwd)/riscv-tools-install"
|
||||
echo " or $(pwd)/esp-tools-install"
|
||||
echo " --ignore-qemu : Ignore installing QEMU"
|
||||
echo " --arch -a : Architecture (e.g., rv64gc)"
|
||||
echo " --help -h : Display this message"
|
||||
exit "$1"
|
||||
}
|
||||
@@ -37,6 +38,7 @@ TOOLCHAIN="riscv-tools"
|
||||
EC2FASTINSTALL="false"
|
||||
IGNOREQEMU=""
|
||||
RISCV=""
|
||||
ARCH=""
|
||||
|
||||
# getopts does not support long options, and is inflexible
|
||||
while [ "$1" != "" ];
|
||||
@@ -48,8 +50,10 @@ do
|
||||
shift
|
||||
RISCV=$(realpath $1) ;;
|
||||
--ignore-qemu )
|
||||
shift
|
||||
IGNOREQEMU="true" ;;
|
||||
-a | --arch )
|
||||
shift
|
||||
ARCH=$1 ;;
|
||||
riscv-tools | esp-tools)
|
||||
TOOLCHAIN=$1 ;;
|
||||
ec2fast )
|
||||
@@ -66,6 +70,15 @@ if [ -z "$RISCV" ] ; then
|
||||
RISCV="$(pwd)/$INSTALL_DIR"
|
||||
fi
|
||||
|
||||
if [ -z "$ARCH" ] ; then
|
||||
XLEN=64
|
||||
elif [[ "$ARCH" =~ ^rv(32|64)((i?m?a?f?d?|g?)c?)$ ]]; then
|
||||
XLEN=${BASH_REMATCH[1]}
|
||||
else
|
||||
error "invalid arch $ARCH"
|
||||
usage 1
|
||||
fi
|
||||
|
||||
echo "Installing toolchain to $RISCV"
|
||||
|
||||
# install risc-v tools
|
||||
@@ -119,7 +132,7 @@ else
|
||||
esac
|
||||
|
||||
module_prepare riscv-gnu-toolchain qemu
|
||||
module_build riscv-gnu-toolchain --prefix="${RISCV}" --with-cmodel=medany
|
||||
module_build riscv-gnu-toolchain --prefix="${RISCV}" --with-cmodel=medany ${ARCH:+--with-arch=${ARCH}}
|
||||
echo '==> Building GNU/Linux toolchain'
|
||||
module_make riscv-gnu-toolchain linux
|
||||
fi
|
||||
@@ -130,15 +143,15 @@ echo '==> Installing libfesvr static library'
|
||||
module_make riscv-isa-sim libfesvr.a
|
||||
cp -p "${SRCDIR}/riscv-isa-sim/build/libfesvr.a" "${RISCV}/lib/"
|
||||
|
||||
CC= CXX= module_all riscv-pk --prefix="${RISCV}" --host=riscv64-unknown-elf
|
||||
module_all riscv-tests --prefix="${RISCV}/riscv64-unknown-elf"
|
||||
CC= CXX= module_all riscv-pk --prefix="${RISCV}" --host=riscv${XLEN}-unknown-elf
|
||||
module_all riscv-tests --prefix="${RISCV}/riscv${XLEN}-unknown-elf" --with-xlen=${XLEN}
|
||||
|
||||
# Common tools (not in any particular toolchain dir)
|
||||
|
||||
CC= CXX= SRCDIR="$(pwd)/toolchains" module_all libgloss --prefix="${RISCV}/riscv64-unknown-elf" --host=riscv64-unknown-elf
|
||||
CC= CXX= SRCDIR="$(pwd)/toolchains" module_all libgloss --prefix="${RISCV}/riscv${XLEN}-unknown-elf" --host=riscv${XLEN}-unknown-elf
|
||||
|
||||
if [ -z "$IGNOREQEMU" ] ; then
|
||||
SRCDIR="$(pwd)/toolchains" module_all qemu --prefix="${RISCV}" --target-list=riscv64-softmmu
|
||||
SRCDIR="$(pwd)/toolchains" module_all qemu --prefix="${RISCV}" --target-list=riscv${XLEN}-softmmu
|
||||
fi
|
||||
|
||||
# make Dromajo
|
||||
|
||||
@@ -18,6 +18,7 @@ sudo yum install -y centos-release-scl
|
||||
sudo yum install -y devtoolset-8-make
|
||||
# install DTC
|
||||
sudo yum install -y dtc
|
||||
sudo yum install -y python
|
||||
|
||||
# install verilator
|
||||
git clone http://git.veripool.org/git/verilator
|
||||
|
||||
8
scripts/entrypoint.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
# used with the dockerfile to set up enviroment variables by running env.sh
|
||||
# adapted from https://stackoverflow.com/questions/55921914/how-to-source-a-script-with-environment-variables-in-a-docker-build-process
|
||||
|
||||
. /home/riscvuser/chipyard/env.sh
|
||||
|
||||
exec "$@"
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
set -ex
|
||||
|
||||
sudo apt-get install -y build-essential bison flex
|
||||
sudo apt-get install -y libgmp-dev libmpfr-dev libmpc-dev zlib1g-dev vim git default-jdk default-jre
|
||||
sudo apt-get install -y build-essential bison flex software-properties-common
|
||||
sudo apt-get install -y libgmp-dev libmpfr-dev libmpc-dev zlib1g-dev vim default-jdk default-jre
|
||||
# install sbt: https://www.scala-sbt.org/release/docs/Installing-sbt-on-Linux.html
|
||||
echo "deb https://dl.bintray.com/sbt/debian /" | sudo tee -a /etc/apt/sources.list.d/sbt.list
|
||||
curl -sL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x2EE0EA64E40A89B84B2DF73499E82A75642AC823" | sudo apt-key add
|
||||
@@ -12,13 +12,18 @@ sudo apt-get install -y sbt
|
||||
sudo apt-get install -y texinfo gengetopt
|
||||
sudo apt-get install -y libexpat1-dev libusb-dev libncurses5-dev cmake
|
||||
# deps for poky
|
||||
sudo apt-get install -y python3.6 patch diffstat texi2html texinfo subversion chrpath git wget
|
||||
sudo apt-get install -y python3.6 patch diffstat texi2html texinfo subversion chrpath wget
|
||||
# deps for qemu
|
||||
sudo apt-get install -y libgtk-3-dev gettext
|
||||
# deps for firemarshal
|
||||
sudo apt-get install -y python3-pip python3.6-dev rsync libguestfs-tools expat ctags
|
||||
# install DTC
|
||||
sudo apt-get install -y device-tree-compiler
|
||||
sudo apt-get install -y python
|
||||
# install git >= 2.17
|
||||
sudo add-apt-repository ppa:git-core/ppa -y
|
||||
sudo apt-get update
|
||||
sudo apt-get install git -y
|
||||
|
||||
# install verilator
|
||||
git clone http://git.veripool.org/git/verilator
|
||||
|
||||
@@ -66,7 +66,7 @@ $(sim_debug): $(sim_vsrcs) $(sim_common_files) $(dramsim_lib) $(EXTRA_SIM_REQS)
|
||||
#########################################################################################
|
||||
.PRECIOUS: $(output_dir)/%.vpd %.vpd
|
||||
$(output_dir)/%.vpd: $(output_dir)/% $(sim_debug)
|
||||
(set -o pipefail && $(sim_debug) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(VERBOSE_FLAGS) +vcdplusfile=$@ $(PERMISSIVE_OFF) $< </dev/null 2> >(spike-dasm > $<.out) | tee $<.log)
|
||||
(set -o pipefail && $(sim_debug) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(SEED_FLAG) $(VERBOSE_FLAGS) +vcdplusfile=$@ $(PERMISSIVE_OFF) $< </dev/null 2> >(spike-dasm > $<.out) | tee $<.log)
|
||||
|
||||
#########################################################################################
|
||||
# general cleanup rules
|
||||
|
||||
@@ -146,7 +146,7 @@ sim_common_files ?= $(build_dir)/sim_files.common.f
|
||||
# java arguments used in sbt
|
||||
#########################################################################################
|
||||
JAVA_HEAP_SIZE ?= 8G
|
||||
JAVA_OPTS ?= -Xmx$(JAVA_HEAP_SIZE) -Xss8M -XX:MaxPermSize=256M
|
||||
JAVA_OPTS ?= -Xmx$(JAVA_HEAP_SIZE) -Xss8M -XX:MaxPermSize=256M -Djava.io.tmpdir=$(base_dir)/.java_tmp
|
||||
|
||||
#########################################################################################
|
||||
# default sbt launch command
|
||||
|
||||