diff --git a/.github/workflows/hdl-build.yaml b/.github/workflows/hdl-build.yaml new file mode 100644 index 0000000..0561321 --- /dev/null +++ b/.github/workflows/hdl-build.yaml @@ -0,0 +1,49 @@ +name: hdl-build +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the $default-branch branch + push: + branches: + - "*" + pull_request: + branches: + - "main" + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +permissions: + contents: read +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + runs-on: macos-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v4 + + # Set up Python + - name: Set up Python 3.13.1 + uses: actions/setup-python@v3 + with: + python-version: "3.13.1" + + # Install Python dependencies and Cocotb + - name: Install dependencies + run: | + python3 -m pip install --upgrade pip + pip install flake8 pytest cocotb + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + + # Install Verilator (MacOS) + - name: Set up Verilator (MacOS) + run: | + brew install verilator + + # Run tests + - name: Run Cocotb + run: | + pytest examples/ \ No newline at end of file diff --git a/.github/workflows/properties/hdl-build.properties.json b/.github/workflows/properties/hdl-build.properties.json new file mode 100644 index 0000000..7e01e23 --- /dev/null +++ b/.github/workflows/properties/hdl-build.properties.json @@ -0,0 +1,6 @@ +{ + "name": "Python AES", + "description": "Create and test a AES Core and Modes.", + "iconName": "python", + "categories": ["Continuous integration", "Python", "Bottle", "Flask"] +} \ No newline at end of file diff --git a/.github/workflows/python-app.yaml b/.github/workflows/python-app.yaml index b2f56fb..1f34177 100644 --- a/.github/workflows/python-app.yaml +++ b/.github/workflows/python-app.yaml @@ -7,10 +7,14 @@ on: push: branches: - "*" + paths-ignore: + - "./.github/workflows/hdl-build.yaml" pull_request: branches: - "main" + workflow_dispatch: + permissions: contents: read @@ -53,4 +57,4 @@ jobs: PYTHONPATH=src pytest test/nist/aesmmt/ -v - name: Test All run: | - PYTHONPATH=src pytest -v \ No newline at end of file + PYTHONPATH=src pytest test/ -v \ No newline at end of file diff --git a/.gitignore b/.gitignore index 75724d1..a00d614 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ -**/.venv -**/.pytest_cache -**/__pycache__ -**/.DS_Store -nist/ \ No newline at end of file +**/.venv/ +**/.pytest_cache/ +**/__pycache__/ +**/.DS_Store/ +nist/ +**/sim_build/ \ No newline at end of file diff --git a/examples/cocotb/quickstart/Makefile b/examples/cocotb/quickstart/Makefile new file mode 100644 index 0000000..9699047 --- /dev/null +++ b/examples/cocotb/quickstart/Makefile @@ -0,0 +1,20 @@ +# This file is public domain, it can be freely copied without restrictions. +# SPDX-License-Identifier: CC0-1.0 + +# Makefile + +# defaults +SIM ?= icarus +TOPLEVEL_LANG ?= verilog + +VERILOG_SOURCES += $(PWD)/my_design.sv +# use VHDL_SOURCES for VHDL files + +# TOPLEVEL is the name of the toplevel module in your Verilog or VHDL file +TOPLEVEL = my_design + +# MODULE is the basename of the Python test file +MODULE = test_my_design + +# include cocotb's make rules to take care of the simulator setup +include $(shell cocotb-config --makefiles)/Makefile.sim diff --git a/examples/cocotb/quickstart/my_design.sv b/examples/cocotb/quickstart/my_design.sv new file mode 100644 index 0000000..458ac8e --- /dev/null +++ b/examples/cocotb/quickstart/my_design.sv @@ -0,0 +1,15 @@ +// This file is public domain, it can be freely copied without restrictions. +// SPDX-License-Identifier: CC0-1.0 + +module my_design(input logic clk); + + timeunit 1ns; + timeprecision 1ns; + + logic my_signal_1; + logic my_signal_2; + + assign my_signal_1 = 1'bx; + assign my_signal_2 = 0; + +endmodule diff --git a/examples/cocotb/quickstart/test_my_design.py b/examples/cocotb/quickstart/test_my_design.py new file mode 100644 index 0000000..fa7a210 --- /dev/null +++ b/examples/cocotb/quickstart/test_my_design.py @@ -0,0 +1,50 @@ +# This file is public domain, it can be freely copied without restrictions. +# SPDX-License-Identifier: CC0-1.0 + +# test_my_design.py (simple) + +import cocotb +from cocotb.triggers import Timer + + +@cocotb.test() +async def my_first_test(dut): + """Try accessing the design.""" + + for cycle in range(10): + dut.clk.value = 0 + await Timer(1, units="ns") + dut.clk.value = 1 + await Timer(1, units="ns") + + dut._log.info("my_signal_1 is %s", dut.my_signal_1.value) + assert dut.my_signal_2.value[0] == 0, "my_signal_2[0] is not 0!" + + +# test_my_design.py (extended) + +import cocotb +from cocotb.triggers import FallingEdge, Timer + + +async def generate_clock(dut): + """Generate clock pulses.""" + + for cycle in range(10): + dut.clk.value = 0 + await Timer(1, units="ns") + dut.clk.value = 1 + await Timer(1, units="ns") + + +@cocotb.test() +async def my_second_test(dut): + """Try accessing the design.""" + + await cocotb.start(generate_clock(dut)) # run the clock "in the background" + + await Timer(5, units="ns") # wait a bit + await FallingEdge(dut.clk) # wait for falling edge/"negedge" + + dut._log.info("my_signal_1 is %s", dut.my_signal_1.value) + assert dut.my_signal_2.value[0] == 0, "my_signal_2[0] is not 0!" diff --git a/examples/cocotb/quickstart/test_runner.py b/examples/cocotb/quickstart/test_runner.py new file mode 100644 index 0000000..f18eb77 --- /dev/null +++ b/examples/cocotb/quickstart/test_runner.py @@ -0,0 +1,29 @@ +# This file is public domain, it can be freely copied without restrictions. +# SPDX-License-Identifier: CC0-1.0 + +# test_runner.py + +import os +from pathlib import Path + +from cocotb.runner import get_runner + + +def test_my_design_runner(): + sim = os.getenv("SIM", "verilator") + + proj_path = Path(__file__).resolve().parent + + sources = [proj_path / "my_design.sv"] + + runner = get_runner(sim) + runner.build( + sources=sources, + hdl_toplevel="my_design", + ) + + runner.test(hdl_toplevel="my_design", test_module="test_my_design,") + + +if __name__ == "__main__": + test_my_design_runner() diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..9aab68b --- /dev/null +++ b/pytest.ini @@ -0,0 +1,7 @@ +# pytest.ini +[pytest] + + +filterwarnings = + # cocotb pytest runners are experimental, ignore this warning + ignore:.*Python runners and associated APIs are an experimental feature.*:UserWarning