From bda8c79457870cb2fc8d6615b8661e41de006bdd Mon Sep 17 00:00:00 2001 From: marwaneltoukhy Date: Sun, 27 Sep 2026 12:10:17 +0300 Subject: [PATCH 1/4] Make cf verify work and add a timer test for the example design - Add a cocotb test for the example 7-segment timer that checks the reset display and the seconds digit counting from 0 to 1. - Add the user_proj_tests lists that `cf verify --all` expects, plus cocotb_tests.py so the runner can find the tests. - Fix hello_world to import from caravel_cocotb. - Replace the stale RTL include list (PicoSoC files) with the real sources, and fill in the empty GL include lists. - Drop the trailing comma in user_proj_timer's port list, which Icarus Verilog rejects. - Ignore the generated sim/ output and design_info.yaml. - README: explain the cf init link/create choice and how cf verify --all picks its tests. Co-authored-by: Cursor --- README.md | 24 +++-- verilog/dv/cocotb/.gitignore | 4 +- verilog/dv/cocotb/cocotb_tests.py | 2 + verilog/dv/cocotb/hello_world/hello_world.py | 6 +- verilog/dv/cocotb/timer/timer.py | 98 +++++++++++++++++++ verilog/dv/cocotb/timer/timer.yaml | 3 + .../user_proj_tests/user_proj_tests.yaml | 6 ++ .../user_proj_tests/user_proj_tests_gl.yaml | 6 ++ .../includes.gl+sdf.caravel_user_project | 5 + .../includes/includes.gl.caravel_user_project | 5 + .../includes.rtl.caravel_user_project | 30 ++---- verilog/rtl/user_proj_timer.v | 2 +- 12 files changed, 155 insertions(+), 36 deletions(-) create mode 100644 verilog/dv/cocotb/cocotb_tests.py create mode 100644 verilog/dv/cocotb/timer/timer.py create mode 100644 verilog/dv/cocotb/timer/timer.yaml create mode 100644 verilog/dv/cocotb/user_proj_tests/user_proj_tests.yaml create mode 100644 verilog/dv/cocotb/user_proj_tests/user_proj_tests_gl.yaml diff --git a/README.md b/README.md index 9de112c..9e821a4 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,14 @@ cd cf init ``` -This creates `.cf/project.json` with project metadata. **This must be run before any other commands** +This creates `.cf/project.json` with project metadata. **This must be run before any other commands.** + +If you are logged in (`cf login`) and this repo is not yet linked to the platform, `cf init` asks which platform action to take: + +1. **Link to an existing platform project** (the default). Use this when the design is already registered on the [ChipFoundry platform](https://platform.chipfoundry.io). Init lists your projects and stores the one you pick in `.cf/project.json`. Later commands, including submission, use that project. Linking is the default so a second platform project is not created by accident. +2. **Create a new platform project**. Use this the first time you register this design. Init asks you to pick a shuttle and creates a Draft project on the platform. + +If you are not logged in, `cf init` only writes the local config. Log in, then run `cf init` again or `cf link`. You can change the link later with `cf link` and `cf unlink`. ### 3. Environment Setup Install the ChipFoundry CLI tool and set up the local environment (PDKs, OpenLane, and OpenFrame): @@ -138,24 +145,27 @@ cf harden openframe_project_wrapper ### Verification #### 1. Simulation -We use cocotb for functional verification. Ensure your file lists are updated in `verilog/includes/`. +We use cocotb for functional verification. Tests live under `verilog/dv/cocotb//`. The template includes `hello_world` and `timer`, which checks the example 7-segment clock (`verilog/rtl/timer.v`) on GPIOs 0–12. + +`cf verify --all` does not discover tests on its own. It runs the list in `verilog/dv/cocotb/user_proj_tests/user_proj_tests.yaml` (and `user_proj_tests_gl.yaml` for gate-level). Add one entry there for each test you want included. Run `cf setup` (cocotb is installed as part of setup) before the first verify. -Run RTL Simulation: +Run one RTL test: ```bash -cf verify +cf verify timer ``` -Run Gate-Level (GL) Simulation: +Run one Gate-Level (GL) test: ```bash -cf verify --sim gl +cf verify timer --sim gl ``` -Run all tests: +Run every test in the list: ```bash cf verify --all +cf verify --all --sim gl ``` --- diff --git a/verilog/dv/cocotb/.gitignore b/verilog/dv/cocotb/.gitignore index 26abdd3..a156244 100644 --- a/verilog/dv/cocotb/.gitignore +++ b/verilog/dv/cocotb/.gitignore @@ -1,2 +1,4 @@ *.pyc -**/.vscode/ \ No newline at end of file +**/.vscode/ +sim/ +design_info.yaml \ No newline at end of file diff --git a/verilog/dv/cocotb/cocotb_tests.py b/verilog/dv/cocotb/cocotb_tests.py new file mode 100644 index 0000000..80959f2 --- /dev/null +++ b/verilog/dv/cocotb/cocotb_tests.py @@ -0,0 +1,2 @@ +from hello_world.hello_world import hello_world +from timer.timer import timer diff --git a/verilog/dv/cocotb/hello_world/hello_world.py b/verilog/dv/cocotb/hello_world/hello_world.py index ffa6c9d..28d699b 100644 --- a/verilog/dv/cocotb/hello_world/hello_world.py +++ b/verilog/dv/cocotb/hello_world/hello_world.py @@ -1,9 +1,9 @@ -from cocotb_includes import test_configure -from cocotb_includes import report_test +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test import cocotb @cocotb.test() @report_test async def hello_world(dut): caravelEnv = await test_configure(dut,timeout_cycles=9373) - cocotb.log.info("Hello World") \ No newline at end of file + cocotb.log.info("Hello World") diff --git a/verilog/dv/cocotb/timer/timer.py b/verilog/dv/cocotb/timer/timer.py new file mode 100644 index 0000000..38528ad --- /dev/null +++ b/verilog/dv/cocotb/timer/timer.py @@ -0,0 +1,98 @@ +# SPDX-FileCopyrightText: 2026 ChipFoundry +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +"""Functional test for the example timer (verilog/rtl/timer.v). + +The wrapper maps the timer as follows: + GPIO 0 user clock + GPIO 1 user reset (active high) + GPIO 5:2 digit enable + GPIO 12:6 seven-segment (common cathode, CC=1) +""" + +from cocotb.triggers import Timer +import cocotb +from caravel_cocotb.caravel_interfaces import report_test, test_configure + +# Common-cathode encodings produced by timer.v with CC=1. +SEG = { + 0: 0b1111110, + 1: 0b0110000, +} +DIGIT_ONES = 0b1110 # dig_cnt == 0, seconds ones +DIGIT_TENS = 0b1101 # dig_cnt == 1, seconds tens + +CLK_GPIO = 0 +RST_GPIO = 1 +# FREQ=2000, so the ones digit increments on user cycle 2001 and is scanned +# out a few cycles later. 2500 clocks covers that without reaching 10 seconds. +USER_CLOCKS = 2500 + + +async def user_clocks(env, count): + for _ in range(count): + env.drive_gpio(CLK_GPIO, 0) + await Timer(10, units="ns") + env.drive_gpio(CLK_GPIO, 1) + await Timer(10, units="ns") + + +def read_display(env): + digit_en = env.monitor_gpio_range((5, 2)) + seven_seg = env.monitor_gpio_range((12, 6)) + return digit_en, seven_seg + + +@cocotb.test() +@report_test +async def timer(dut): + env = await test_configure(dut, timeout_cycles=20000) + + env.drive_gpio(RST_GPIO, 1) + await user_clocks(env, 4) + digit_en, seven_seg = read_display(env) + assert (digit_en, seven_seg) == (DIGIT_ONES, SEG[0]), ( + f"reset display was digit_en={digit_en:04b} seven_seg={seven_seg:07b}, " + f"expected {DIGIT_ONES:04b} {SEG[0]:07b}" + ) + + env.drive_gpio(RST_GPIO, 0) + saw_zero = False + saw_one = False + for _ in range(USER_CLOCKS): + await user_clocks(env, 1) + digit_en, seven_seg = read_display(env) + if digit_en == DIGIT_ONES: + if seven_seg == SEG[0]: + saw_zero = True + elif seven_seg == SEG[1]: + if not saw_zero: + raise AssertionError("seconds ones showed 1 before 0") + saw_one = True + else: + raise AssertionError( + f"unexpected seconds-ones pattern {seven_seg:07b}" + ) + elif digit_en == DIGIT_TENS and seven_seg != SEG[0]: + raise AssertionError( + f"seconds tens changed during the first second: {seven_seg:07b}" + ) + + assert saw_zero and saw_one, ( + "seconds ones digit did not count from 0 to 1 " + f"(saw 0={saw_zero}, saw 1={saw_one})" + ) + cocotb.log.info("[timer] seconds digit counted from 0 to 1") diff --git a/verilog/dv/cocotb/timer/timer.yaml b/verilog/dv/cocotb/timer/timer.yaml new file mode 100644 index 0000000..af97047 --- /dev/null +++ b/verilog/dv/cocotb/timer/timer.yaml @@ -0,0 +1,3 @@ +--- +Tests: + - {name: timer, sim: RTL} diff --git a/verilog/dv/cocotb/user_proj_tests/user_proj_tests.yaml b/verilog/dv/cocotb/user_proj_tests/user_proj_tests.yaml new file mode 100644 index 0000000..b180c3e --- /dev/null +++ b/verilog/dv/cocotb/user_proj_tests/user_proj_tests.yaml @@ -0,0 +1,6 @@ +--- +# Test list for `cf verify --all` (RTL). +# Add one entry per cocotb test under verilog/dv/cocotb//. +Tests: + - {name: hello_world, sim: RTL} + - {name: timer, sim: RTL} diff --git a/verilog/dv/cocotb/user_proj_tests/user_proj_tests_gl.yaml b/verilog/dv/cocotb/user_proj_tests/user_proj_tests_gl.yaml new file mode 100644 index 0000000..103b273 --- /dev/null +++ b/verilog/dv/cocotb/user_proj_tests/user_proj_tests_gl.yaml @@ -0,0 +1,6 @@ +--- +# Test list for `cf verify --all --sim gl`. +# Add one entry per cocotb test under verilog/dv/cocotb//. +Tests: + - {name: hello_world, sim: GL} + - {name: timer, sim: GL} diff --git a/verilog/includes/includes.gl+sdf.caravel_user_project b/verilog/includes/includes.gl+sdf.caravel_user_project index e69de29..5068462 100644 --- a/verilog/includes/includes.gl+sdf.caravel_user_project +++ b/verilog/includes/includes.gl+sdf.caravel_user_project @@ -0,0 +1,5 @@ +# OpenFrame user project GL+SDF includes +-v $(USER_PROJECT_VERILOG)/gl/vccd1_connection.v +-v $(USER_PROJECT_VERILOG)/gl/vssd1_connection.v +-v $(USER_PROJECT_VERILOG)/gl/user_proj_timer.v +-v $(USER_PROJECT_VERILOG)/gl/openframe_project_wrapper.v diff --git a/verilog/includes/includes.gl.caravel_user_project b/verilog/includes/includes.gl.caravel_user_project index e69de29..f5598b0 100644 --- a/verilog/includes/includes.gl.caravel_user_project +++ b/verilog/includes/includes.gl.caravel_user_project @@ -0,0 +1,5 @@ +# OpenFrame user project GL includes +-v $(USER_PROJECT_VERILOG)/gl/vccd1_connection.v +-v $(USER_PROJECT_VERILOG)/gl/vssd1_connection.v +-v $(USER_PROJECT_VERILOG)/gl/user_proj_timer.v +-v $(USER_PROJECT_VERILOG)/gl/openframe_project_wrapper.v diff --git a/verilog/includes/includes.rtl.caravel_user_project b/verilog/includes/includes.rtl.caravel_user_project index 656289d..4ea2fa3 100644 --- a/verilog/includes/includes.rtl.caravel_user_project +++ b/verilog/includes/includes.rtl.caravel_user_project @@ -1,25 +1,7 @@ -# Caravel user project includes --v $(USER_PROJECT_VERILOG)/dv/firmware/spiflash.v +# OpenFrame user project RTL includes -v $(USER_PROJECT_VERILOG)/../ip/CF_gpio_config/rtl/CF_gpio_config.v --v $(USER_PROJECT_VERILOG)/rtl/openframe_project_wrapper.v --v $(USER_PROJECT_VERILOG)/rtl/picosoc.v --v $(USER_PROJECT_VERILOG)/rtl/picorv32.v --v $(USER_PROJECT_VERILOG)/rtl/spimemio.v --v $(USER_PROJECT_VERILOG)/rtl/simpleuart.v --v $(USER_PROJECT_VERILOG)/rtl/clock_routing.v --v $(USER_PROJECT_VERILOG)/rtl/clock_div.v --v $(USER_PROJECT_VERILOG)/rtl/housekeeping.v --v $(USER_PROJECT_VERILOG)/rtl/housekeeping_spi.v --v $(USER_PROJECT_VERILOG)/rtl/digital_locked_loop.v --v $(USER_PROJECT_VERILOG)/rtl/dll_controller.v --v $(USER_PROJECT_VERILOG)/rtl/ring_osc2x13.v --v $(USER_PROJECT_VERILOG)/rtl/simple_spi_master.v --v $(USER_PROJECT_VERILOG)/rtl/counter_timer_high.v --v $(USER_PROJECT_VERILOG)/rtl/counter_timer_low.v --v $(USER_PROJECT_VERILOG)/rtl/intercon_wb.v --v $(USER_PROJECT_VERILOG)/rtl/mem_wb.v --v $(USER_PROJECT_VERILOG)/rtl/gpio_wb.v --v $(USER_PROJECT_VERILOG)/rtl/gpio_vector_wb.v --v $(USER_PROJECT_VERILOG)/rtl/debug_regs.v - - \ No newline at end of file +-v $(USER_PROJECT_VERILOG)/rtl/vccd1_connection.v +-v $(USER_PROJECT_VERILOG)/rtl/vssd1_connection.v +-v $(USER_PROJECT_VERILOG)/rtl/timer.v +-v $(USER_PROJECT_VERILOG)/rtl/user_proj_timer.v +-v $(USER_PROJECT_VERILOG)/rtl/openframe_project_wrapper.v diff --git a/verilog/rtl/user_proj_timer.v b/verilog/rtl/user_proj_timer.v index 309cb9f..aab32e4 100644 --- a/verilog/rtl/user_proj_timer.v +++ b/verilog/rtl/user_proj_timer.v @@ -46,7 +46,7 @@ module user_proj_timer ( input wb_rst_i, // IOs - output [10:0] io_out, + output [10:0] io_out ); wire [6:0] seven_seg; From c38f7d407d12c089ffb0de324ae0138d07f61fe0 Mon Sep 17 00:00:00 2001 From: marwaneltoukhy Date: Sun, 27 Sep 2026 12:25:36 +0300 Subject: [PATCH 2/4] Fix CI hardening and RTL verification Pin CF_gpio_config to v1.1.0, the latest version in the IP index. v1.1.4 is not published there, so ipm installed nothing and LibreLane failed looking for the missing RTL. Fail the job if that file is absent. Install caravel_cocotb from caravel-sim-infrastructure and pass --openframe, so CI runs the cocotb tests instead of compiling Caravel firmware. Co-authored-by: Cursor --- .github/workflows/user_project_ci.yml | 3 ++- Makefile | 10 +++++----- ip/dependencies.json | 2 +- verilog/dv/cocotb/hello_world/hello_world.c | 3 +-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/user_project_ci.yml b/.github/workflows/user_project_ci.yml index cefe273..0d84926 100644 --- a/.github/workflows/user_project_ci.yml +++ b/.github/workflows/user_project_ci.yml @@ -159,6 +159,7 @@ jobs: python3 -m pip install --upgrade --no-cache-dir cf-ipm curl -fsSL -o /tmp/verified_IPs.json https://raw.githubusercontent.com/chipfoundry/ipm/main/verified_IPs.json ipm install-dep --ip-root $GITHUB_WORKSPACE/ip --local-file /tmp/verified_IPs.json + test -f $GITHUB_WORKSPACE/ip/CF_gpio_config/rtl/CF_gpio_config.v - name: Download PDK Tarball uses: actions/download-artifact@v4 @@ -315,7 +316,7 @@ jobs: - name: run RTL verification if: env.RUN_RTL == 'true' run: | - cd $GITHUB_WORKSPACE/verilog/dv/cocotb && $GITHUB_WORKSPACE/venv-cocotb/bin/caravel_cocotb -tl user_proj_tests/user_proj_tests.yaml -verbosity debug --CI -tag rtl_verification + cd $GITHUB_WORKSPACE/verilog/dv/cocotb && $GITHUB_WORKSPACE/venv-cocotb/bin/caravel_cocotb --openframe -tl user_proj_tests/user_proj_tests.yaml -verbosity debug --CI -tag rtl_verification cnt=$(grep -c "failed" "$GITHUB_WORKSPACE/verilog/dv/cocotb/sim/rtl_verification/runs.log") if ! [[ $cnt ]]; then cnt=0; fi if [[ $cnt -eq 1 ]]; then exit 0; fi diff --git a/Makefile b/Makefile index e56b0fe..9daa34e 100644 --- a/Makefile +++ b/Makefile @@ -318,7 +318,7 @@ install-caravel-cocotb: rm -rf ./venv-cocotb $(PYTHON_BIN) -m venv ./venv-cocotb ./venv-cocotb/bin/$(PYTHON_BIN) -m pip install --upgrade --no-cache-dir pip - ./venv-cocotb/bin/$(PYTHON_BIN) -m pip install --upgrade --no-cache-dir caravel-cocotb + ./venv-cocotb/bin/$(PYTHON_BIN) -m pip install --upgrade --no-cache-dir "git+https://github.com/chipfoundry/caravel-sim-infrastructure.git@main#subdirectory=cocotb" .PHONY: setup-cocotb-env setup-cocotb-env: @@ -329,17 +329,17 @@ setup-cocotb: install-caravel-cocotb setup-cocotb-env simenv-cocotb .PHONY: cocotb-verify-all-rtl cocotb-verify-all-rtl: - @(cd $(PROJECT_ROOT)/verilog/dv/cocotb && $(PROJECT_ROOT)/venv-cocotb/bin/caravel_cocotb -tl user_proj_tests/user_proj_tests.yaml ) + @(cd $(PROJECT_ROOT)/verilog/dv/cocotb && $(PROJECT_ROOT)/venv-cocotb/bin/caravel_cocotb --openframe -tl user_proj_tests/user_proj_tests.yaml ) .PHONY: cocotb-verify-all-gl cocotb-verify-all-gl: - @(cd $(PROJECT_ROOT)/verilog/dv/cocotb && $(PROJECT_ROOT)/venv-cocotb/bin/caravel_cocotb -tl user_proj_tests/user_proj_tests_gl.yaml -sim GL) + @(cd $(PROJECT_ROOT)/verilog/dv/cocotb && $(PROJECT_ROOT)/venv-cocotb/bin/caravel_cocotb --openframe -tl user_proj_tests/user_proj_tests_gl.yaml -sim GL) $(cocotb-dv-targets-rtl): cocotb-verify-%-rtl: - @(cd $(PROJECT_ROOT)/verilog/dv/cocotb && $(PROJECT_ROOT)/venv-cocotb/bin/caravel_cocotb -t $* ) + @(cd $(PROJECT_ROOT)/verilog/dv/cocotb && $(PROJECT_ROOT)/venv-cocotb/bin/caravel_cocotb --openframe -t $* ) $(cocotb-dv-targets-gl): cocotb-verify-%-gl: - @(cd $(PROJECT_ROOT)/verilog/dv/cocotb && $(PROJECT_ROOT)/venv-cocotb/bin/caravel_cocotb -t $* -sim GL) + @(cd $(PROJECT_ROOT)/verilog/dv/cocotb && $(PROJECT_ROOT)/venv-cocotb/bin/caravel_cocotb --openframe -t $* -sim GL) ./verilog/gl/user_project_wrapper.v: $(error you don't have $@) diff --git a/ip/dependencies.json b/ip/dependencies.json index 831b646..3323913 100644 --- a/ip/dependencies.json +++ b/ip/dependencies.json @@ -1,7 +1,7 @@ { "IP": [ { - "CF_gpio_config": "v1.1.4" + "CF_gpio_config": "v1.1.0" } ] } diff --git a/verilog/dv/cocotb/hello_world/hello_world.c b/verilog/dv/cocotb/hello_world/hello_world.c index 6199adc..b4fda51 100644 --- a/verilog/dv/cocotb/hello_world/hello_world.c +++ b/verilog/dv/cocotb/hello_world/hello_world.c @@ -1,4 +1,3 @@ -#include void main(){ return; -} \ No newline at end of file +} From 0a741a57f642a775aee37d8f9d124de95fb7a92d Mon Sep 17 00:00:00 2001 From: marwaneltoukhy Date: Sun, 27 Sep 2026 12:36:18 +0300 Subject: [PATCH 3/4] Install CF_gpio_config from the platform catalog v1.1.4 is published on the ChipFoundry catalog. CI was forcing the GitHub verified_IPs.json, which only lists v1.1.0, so the install failed. Drop --local-file and keep the v1.1.4 dependency. Co-authored-by: Cursor --- .github/workflows/user_project_ci.yml | 3 +-- ip/dependencies.json | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/user_project_ci.yml b/.github/workflows/user_project_ci.yml index 0d84926..cc76800 100644 --- a/.github/workflows/user_project_ci.yml +++ b/.github/workflows/user_project_ci.yml @@ -157,8 +157,7 @@ jobs: - name: Install IPM dependencies run: | python3 -m pip install --upgrade --no-cache-dir cf-ipm - curl -fsSL -o /tmp/verified_IPs.json https://raw.githubusercontent.com/chipfoundry/ipm/main/verified_IPs.json - ipm install-dep --ip-root $GITHUB_WORKSPACE/ip --local-file /tmp/verified_IPs.json + ipm install-dep --ip-root $GITHUB_WORKSPACE/ip test -f $GITHUB_WORKSPACE/ip/CF_gpio_config/rtl/CF_gpio_config.v - name: Download PDK Tarball diff --git a/ip/dependencies.json b/ip/dependencies.json index 3323913..831b646 100644 --- a/ip/dependencies.json +++ b/ip/dependencies.json @@ -1,7 +1,7 @@ { "IP": [ { - "CF_gpio_config": "v1.1.0" + "CF_gpio_config": "v1.1.4" } ] } From da383c6002713098e58dca1cc6f8d3c3dadce7fb Mon Sep 17 00:00:00 2001 From: marwaneltoukhy Date: Sun, 27 Sep 2026 20:14:41 +0300 Subject: [PATCH 4/4] Install IPM dependencies before RTL verification The RTL job compiles CF_gpio_config.v but never installed it, so Icarus aborted and reported a missing caravel_top. Co-authored-by: Cursor --- .github/workflows/user_project_ci.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/user_project_ci.yml b/.github/workflows/user_project_ci.yml index cc76800..9140c40 100644 --- a/.github/workflows/user_project_ci.yml +++ b/.github/workflows/user_project_ci.yml @@ -307,6 +307,13 @@ jobs: sudo chown -R $USER:$USER ${{ env.MCW_ROOT }} tar -xf /tmp/mgmt_core_wrapper.tar -C $MCW_ROOT . + - name: Install IPM dependencies + if: env.RUN_RTL == 'true' + run: | + python3 -m pip install --upgrade --no-cache-dir cf-ipm + ipm install-dep --ip-root $GITHUB_WORKSPACE/ip + test -f $GITHUB_WORKSPACE/ip/CF_gpio_config/rtl/CF_gpio_config.v + - name: install cocotb if: env.RUN_RTL == 'true' run: |