diff --git a/.github/workflows/user_project_ci.yml b/.github/workflows/user_project_ci.yml index cefe273..9140c40 100644 --- a/.github/workflows/user_project_ci.yml +++ b/.github/workflows/user_project_ci.yml @@ -157,8 +157,8 @@ 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 uses: actions/download-artifact@v4 @@ -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: | @@ -315,7 +322,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/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.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 +} 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;