Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update synthesis docs #454

Merged
merged 24 commits into from
Dec 18, 2023
Merged
Changes from 13 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2f6159b
Update synthesis docs.
Jul 27, 2023
f663a24
Update syntax errors
lekcyjna123 Nov 13, 2023
ebae77d
Fix errors
lekcyjna123 Nov 13, 2023
996b088
Merge branch 'master' into lekcyjna/update-synthesis-doc
lekcyjna123 Nov 13, 2023
59635ed
Apply suggestions from code review
lekcyjna123 Nov 18, 2023
5fd1c3d
Merge branch 'master' into lekcyjna/update-synthesis-doc
lekcyjna123 Nov 18, 2023
d7ba0bc
WIP. Reformat Synthesise page withe the goal to describe all verifica…
Nov 18, 2023
761a624
Add links
Nov 19, 2023
9322ff8
First version about benchmarking
Nov 19, 2023
7b06a81
Benchmarking commands before verification.
Nov 19, 2023
d764456
Fixes in commands
Nov 19, 2023
79d6aea
Add section about regression.
Nov 19, 2023
18f447e
Fix typos.
Nov 19, 2023
a262621
Apply suggestions from code review
lekcyjna123 Nov 19, 2023
ff2cdb4
Done some magic to correct Benchmarking section.
Nov 19, 2023
363609d
Fix IPC introduction
Nov 19, 2023
5d89258
Update docs/synthesis/Synthesis.md
tilk Dec 1, 2023
4a70573
Merge branch 'master' into lekcyjna/update-synthesis-doc
Dec 3, 2023
b9aad40
Merge branch 'lekcyjna/update-synthesis-doc' of github.com:kuznia-rdz…
Dec 3, 2023
f916ed0
Merge branch 'master' into lekcyjna/update-synthesis-doc
lekcyjna123 Dec 3, 2023
262b6f4
Update docker tags to latest
Dec 3, 2023
f215c3b
Merge branch 'lekcyjna/update-synthesis-doc' of github.com:kuznia-rdz…
Dec 3, 2023
c7a855b
Merge branch 'master' into lekcyjna/update-synthesis-doc
lekcyjna123 Dec 15, 2023
6e9f84c
Merge branch 'master' into lekcyjna/update-synthesis-doc
tilk Dec 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 144 additions & 31 deletions docs/synthesis/Synthesis.md
Original file line number Diff line number Diff line change
@@ -1,49 +1,162 @@
# Synthesis
# Core verification

CoreBlocks synthesizes `Core` circuit to test how many resources it consumes as the project
grows and more functionalities are added.
Coreblocks is verified at several levels of abstraction. Beside of unit tests and module tests, we also
synthesise the core to the ECP5 FPGA target, to check that it can work in reality. Performance is verified
using synthesis results and a set of benchmarks simulated with cycle precision in cocotb. We also verify
correctness of the core behaviour by running assembler tests from [riscv-tests](https://github.com/riscv-software-src/riscv-tests/tree/master)
and [riscv-arch-tests](https://github.com/riscv-non-isa/riscv-arch-test).

## Documentation
These three verification steps are automatically run by CI on every commit delivered to the `master` branch. Running
the checks in CI allow us to collect historical data, which are available in the form of the graphs
on a dedicated [benchmark subpage](https://kuznia-rdzeni.github.io/coreblocks/dev/benchmark/).

### Requirements
In CI we use pre-built docker containers, which are publicly available on our [github page](https://github.com/orgs/kuznia-rdzeni/packages).
In the following subsections we provide the instructions on how to manually run verification steps using these containers.
They can be recreated using standard docker build commands:

In order to perform synthesis you will need to install following tools:
* [yosys](https://github.com/YosysHQ/yosys)
* [prjtrellis](https://github.com/YosysHQ/prjtrellis)
* [nextpnr-ecp5](https://github.com/YosysHQ/nextpnr.git)

These tools may need manual compilation from git repository, that can take some time.

You can use docker images that have installed all required tools to perform synthesis:
* [vuush/amaranth-synth:ecp5](https://hub.docker.com/r/vuush/amaranth-synth/tags)

To build the `AmaranthSynthECP5.Dockerfile` yourself use following command:
```
docker build --platform linux/amd64 -t "amaranth-synth:ecp5" -f ./docker/AmaranthSynthECP5.Dockerfile .
```

### Usage

Script named `synthesize.py` is used to perform the `Core` synthesis.

Example usage:
```
./scripts/synthesize.py --help
./scripts/synthesize.py --platform ecp5 --verbose
```
## Synthesis

To collect synthesis information we use script named `parse_benchmark_info.py`.
The basic step in verification is to see if it is possible to synthesise the `Core` circuit. This allows us to
control the level of complexity of the core. Although Coreblocks is an educational core, we want it to be practical, not theoretical,
so it should have an acceptable maximum frequency and shouldn't use too many resources, so it can be run
on a FPGA. The synthesis step ensures that these requirements are met. In addition, it checks whether the code that is acceptable
lekcyjna123 marked this conversation as resolved.
Show resolved Hide resolved
for the Amaranth is also acceptable for the synthesis tools.

This script parses the output of the synthesis tool and extracts the
following information:
The main properties collected in the synthesis step:
- Max clock frequency
- Number of logic cells used
- Number of carry cells used
- Number of RAM cells used
- Number of DFF cells used

## Benchmarks
The configuration of the docker container is described in the `AmaranthSynthECP5.Dockerfile`, which can be found in
[our repo](https://github.com/orgs/kuznia-rdzeni/packages/container/package/amaranth-synth).

### Manual reproduction

```bash
sudo docker pull ghcr.io/kuznia-rdzeni/amaranth-synth:ecp5-3.11
sudo docker run -it --rm ghcr.io/kuznia-rdzeni/amaranth-synth:ecp5-3.11
git clone --depth=1 https://github.com/kuznia-rdzeni/coreblocks.git
cd coreblocks
apt update
apt install python3.11-venv
python3 -m venv venv
. venv/bin/activate
python3 -m pip install --upgrade pip
pip3 install -r requirements-dev.txt
lekcyjna123 marked this conversation as resolved.
Show resolved Hide resolved
PYTHONHASHSEED=0 ./scripts/synthesize.py --verbose --config full
./scripts/parse_benchmark_info.py
cat benchmark.json
```

The main point of the above listing is the `synthesize.py` script, which creates an instance of the `Core` object with
the configuration provided by the user and then passes it to the Amaranth to generate a Verilog description from that instance.
lekcyjna123 marked this conversation as resolved.
Show resolved Hide resolved
This description is then processed by the Yosys and nextpnr-ecp5 to generate the ECP5 bitstream.
lekcyjna123 marked this conversation as resolved.
Show resolved Hide resolved

The strength of the Coreblocks is its modularity, so we can provide different configurations with little effort. You can choose
lekcyjna123 marked this conversation as resolved.
Show resolved Hide resolved
a configuration to synthesise using the `--config` argument to the `synthesise.py` script.

For each commit on `master` branch, CI runs the synthesis and saves the parameters collected by `parse_benchmark_info` script.
### Dependencies

Graphs generated from this information are available on a dedicated [subpage](https://kuznia-rdzeni.github.io/coreblocks/dev/benchmark/).
In order to perform synthesis we use:
* [yosys](https://github.com/YosysHQ/yosys) - to synthesise the Verilog generated by Amaranth up to gate level
* [nextpnr-ecp5](https://github.com/YosysHQ/nextpnr.git) - to perform the "Place and Route" step
* [prjtrellis](https://github.com/YosysHQ/prjtrellis) - provides the description of the ECP5 bitstream format
lekcyjna123 marked this conversation as resolved.
Show resolved Hide resolved

## Benchmarking
tilk marked this conversation as resolved.
Show resolved Hide resolved

The maximum clock frequency determined by synthesis isn't the only measure of performance. Theoretically, there is always a
possibility to increase Fmax by increasing the latency. To avoid the pitfall of too big latency, we have introduced the monitoring
lekcyjna123 marked this conversation as resolved.
Show resolved Hide resolved
of instructions executed per clock cycle (IPC). This is done by simulating the core with cycle accuracy and running
tilk marked this conversation as resolved.
Show resolved Hide resolved
benchmarks written in C on such core. As benchmarking programs we use
lekcyjna123 marked this conversation as resolved.
Show resolved Hide resolved
[embench](https://github.com/embench/embench-iot/tree/master).

The benchmarking is done in two steps. First, we compile C programs into binary format and then run the binaries on
simulated core. The compilation is done using [riscv-gnu-toolchain](https://github.com/riscv/riscv-gnu-toolchain), with
lekcyjna123 marked this conversation as resolved.
Show resolved Hide resolved
glibc compiled for different architectural subsets of RISC-V extensions. The configuration of the riscv-gnu-toolchain used in
Coreblocks is described in [riscv-toolchain.Dockerfile](https://github.com/kuznia-rdzeni/coreblocks/blob/master/docker/riscv-toolchain.Dockerfile).
Benchmarks can be compiled once and used repeatedly as long as there is no need to add support for the new
RISC-V extensions or the embench isn't be updated.
lekcyjna123 marked this conversation as resolved.
Show resolved Hide resolved

Once we have binaries, we can execute them in simulation. This is done with [Cocotb](https://github.com/cocotb/cocotb) and
[Verilator](https://github.com/verilator/verilator). First we generate Verilog code describing Coreblocks instance.
Then it is passed to Verilator for compilation and Cocotb controls the execution of the program, by stubbing external
interfaces. Compiled Verilator in a compatible version is available in [Verilator.Dockerfile](https://github.com/kuznia-rdzeni/coreblocks/blob/master/docker/Verilator.Dockerfile).

### Benchmarks manual execution
```bash
# ========== STEP 1: Compilation ==========
# Clone coreblocks into host file system
git clone --depth=1 https://github.com/kuznia-rdzeni/coreblocks.git
cd coreblocks
git submodule update --init --recursive
cd ..
sudo docker pull ghcr.io/kuznia-rdzeni/riscv-toolchain:2023.10.08_v
# Run docker with the coreblocks directory mounted into it
sudo docker run -v ./coreblocks:/coreblocks -it --rm ghcr.io/kuznia-rdzeni/riscv-toolchain:2023.10.08_v
cd /coreblocks/test/external/embench
# Compilation will put binaries in the subdirectory of the /coreblocks directory, which is shared with the host
# so that binaries survive after the docker container is closed
make
exit

# ========== STEP 2: Execution ==========
sudo docker pull ghcr.io/kuznia-rdzeni/verilator:v5.008-3.11
# Run docker with the coreblocks directory mounted into it. This directory contains
# benchmark binaries after running the first step.
sudo docker run -v ./coreblocks:/coreblocks -it --rm ghcr.io/kuznia-rdzeni/verilator:v5.008-3.11
apt update
apt install python3.11-venv
python3 -m venv venv
. venv/bin/activate
python3 -m pip install --upgrade pip
cd coreblocks
pip3 install -r requirements-dev.txt
PYTHONHASHSEED=0 ./scripts/gen_verilog.py --verbose --config full
./scripts/run_benchmarks.py
```

## Regression tests

Regression tests should ensure that Coreblocks is complaint with RISC-V specification requirements. Tests include
tilk marked this conversation as resolved.
Show resolved Hide resolved
assembler programs that tests entire RISC-V instruction set. We execute these programs in a similar way to benchmarks.
So, as a first step, we compile the programs to the binary format and then we run them on core simulated by Verilator
and Cocotb.

### Regression tests manual execution
```bash
# ========== STEP 1: Compilation ==========
# Clone coreblocks into host file system
git clone --depth=1 https://github.com/kuznia-rdzeni/coreblocks.git
cd coreblocks
git submodule update --init --recursive
cd ..
sudo docker pull ghcr.io/kuznia-rdzeni/riscv-toolchain:2023.10.08_v
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest having a latest tag to avoid updating this doc on every docker change. This needs to be changed on other lines too.

Suggested change
sudo docker pull ghcr.io/kuznia-rdzeni/riscv-toolchain:2023.10.08_v
sudo docker pull ghcr.io/kuznia-rdzeni/riscv-toolchain:latest

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But we don't use the tag latest.

sudo docker pull ghcr.io/kuznia-rdzeni/riscv-toolchain:latest

That command doesn't work.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we don't. Maybe we should? (That was the suggestion.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should have two sets of tags? One to use in pipelines to allow easy tracking of changes and second tag latest for the documentation? Or maybe we should use only the latest tag and use checksums in pipelines?

I don't want to use latest in pipelines, because that will cause some tricky errors (e.g. updating dockers in preparation for Dockerfile change, while some other review is being tested).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added latest tag to verilog and amaranth-synth packages. To add tag to the riscv-toolchain I have to download it first.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

riscv-toolchain have been also tagged with latest

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want to use latest in pipelines, because that will cause some tricky errors (e.g. updating dockers in preparation for Dockerfile change, while some other review is being tested).

Workflows should reference concrete versions, latest should be for convenience only.

# Run docker with the coreblocks directory mounted into it
sudo docker run -v ./coreblocks:/coreblocks -it --rm ghcr.io/kuznia-rdzeni/riscv-toolchain:2023.10.08_v
cd /coreblocks/test/external/riscv-tests
# Compilation will put binaries in the subdirectory of the /coreblocks directory, which is shared with the host
# so that binaries survive after the docker container is closed
make
exit

# ========== STEP 2: Execution ==========
sudo docker pull ghcr.io/kuznia-rdzeni/verilator:v5.008-3.11
# Run docker with the coreblocks directory mounted into it. This directory contains
# regression test binaries after running the first step.
sudo docker run -v ./coreblocks:/coreblocks -it --rm ghcr.io/kuznia-rdzeni/verilator:v5.008-3.11
apt update
apt install python3.11-venv
python3 -m venv venv
. venv/bin/activate
python3 -m pip install --upgrade pip
cd coreblocks
pip3 install -r requirements-dev.txt
PYTHONHASHSEED=0 ./scripts/gen_verilog.py --verbose --config full
./scripts/run_tests.py -a regression
```