diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 7f06066c..2c2c5a17 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -25,6 +25,21 @@ jobs: - name: Set up PDM uses: pdm-project/setup-pdm@v4 + - name: Generate overrides to use current branch if PR + if: github.event_name == 'pull_request' + run: | + pdm run tools/gen_overrides.py ${{github.head_ref}} > overrides.txt + echo "Generated overrides:" + cat overrides.txt + + - name: Relock PDM + if: github.event_name != 'pull_request' + run: pdm lock -d + + - name: Relock PDM (PR) + if: github.event_name == 'pull_request' + run: pdm lock -d --override overrides.txt + - name: Install dependencies run: | pdm install diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index fa999720..be0b73fc 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -15,10 +15,25 @@ jobs: steps: - name: Check out source code uses: actions/checkout@v4 - with: - fetch-depth: 0 + - name: Set up PDM uses: pdm-project/setup-pdm@v4 + + - name: Generate overrides to use current branch if PR + if: github.event_name == 'pull_request' + run: | + pdm run tools/gen_overrides.py ${{github.head_ref}} > overrides.txt + echo "Generated overrides:" + cat overrides.txt + + - name: Relock PDM + if: github.event_name != 'pull_request' + run: pdm lock -d + + - name: Relock PDM (PR) + if: github.event_name == 'pull_request' + run: pdm lock -d --override overrides.txt + - name: Install dependencies run: | pdm install @@ -39,75 +54,83 @@ jobs: with: fetch-depth: 0 - name: Check source code licenses - run: | - docker run --platform=linux/amd64 -v ${PWD}:/src ghcr.io/google/addlicense -v -check -l BSD-2-Clause -c "ChipFlow" -s=only -ignore **/__init__.py **/*.py + run: ./tools/license_check.sh test-submit: runs-on: ubuntu-latest + strategy: + matrix: + dry: [true, false] + repo: + - name: "ChipFlow/chipflow-examples" + design: "minimal" + - name: "ChipFlow/chipflow-test-socs" + design: "sram" + env: + DRY: ${{ matrix.dry && '--dry-run' || '' }} + is_dry: ${{ matrix.dry && '(dry run)' || '' }} + our_path: "${{ github.workspace}}/${{ github.repo }}" + test_repo_path: "${{ github.workspace }}/${{ matrix.repo.name }}" + + name: ${{ matrix.dry && 'Test Submit - Dry run' || 'Test submit' }} + steps: - name: Check out source code uses: actions/checkout@v4 with: - fetch-depth: 0 - path: chipflow-lib - - name: Check out chipflow-examples + path: ${{ env.our_path }} + + - name: Check out ${{ matrix.repo.name }} uses: actions/checkout@v4 with: - repository: ChipFlow/chipflow-examples - fetch-depth: 0 - path: chipflow-examples + repository: ${{ matrix.repo.name }} + path: ${{ env.test_repo_path }} + + - name: Check for branch ${{ github.head_ref }} + working-directory: ${{ env.test_repo_path }} + if: github.event_name == 'pull_request' + run: | + git checkout ${{ github.head_ref }} || echo "Falling back to main" - name: Set up PDM uses: pdm-project/setup-pdm@v4 with: - python-version: "3.10" + python-version: '3.10' cache: true - cache-dependency-path: "./**/pyproject.toml" - - name: Install dependencies - working-directory: ./chipflow-examples - run: | - pdm install - pdm run python -m ensurepip - pdm run python -m pip install -e ../chipflow-lib - - name: Run tests - working-directory: ./chipflow-examples + cache-dependency-path: './**/pyproject.toml' + + - name: Generate overrides to use current branch if PR + working-directory: ${{ env.test_repo_path }} + if: github.event_name == 'pull_request' run: | - pdm test - pdm run chipflow pin lock - pdm run chipflow silicon submit --wait - env: - CHIPFLOW_API_KEY: ${{ secrets.CHIPFLOW_API_KEY}} + pdm run ${{env.our_path}}/tools/gen_overrides.py ${{github.head_ref}} > overrides.txt + echo "Generated overrides:" + cat overrides.txt - test-submit-dry: - runs-on: ubuntu-latest - steps: - - name: Check out source code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - path: chipflow-lib - - name: Check out chipflow-examples - uses: actions/checkout@v4 - with: - repository: ChipFlow/chipflow-examples - fetch-depth: 0 - path: chipflow-examples + - name: Relock PDM + working-directory: ${{ env.test_repo_path }} + if: github.event_name != 'pull_request' + run: pdm lock -d + + - name: Relock PDM (PR) + working-directory: ${{ env.test_repo_path }} + if: github.event_name == 'pull_request' + run: pdm lock -d --override overrides.txt - - name: Set up PDM - uses: pdm-project/setup-pdm@v4 - with: - python-version: "3.10" - cache: true - cache-dependency-path: "./**/pyproject.toml" - name: Install dependencies - working-directory: ./chipflow-examples + working-directory: ${{ env.test_repo_path }} run: | pdm install - pdm run python -m ensurepip - pdm run python -m pip install -e ../chipflow-lib + - name: Run tests - working-directory: ./chipflow-examples + working-directory: ${{ env.test_repo_path }} run: | pdm test + + - name: Submit build ${{ env.is_dry }} + working-directory: ${{ env.test_repo_path }}/${{ matrix.repo.design }} + run: | pdm run chipflow pin lock - pdm run chipflow silicon submit --dry-run + pdm run chipflow silicon submit --wait $DRY + env: + CHIPFLOW_API_KEY: ${{ secrets.CHIPFLOW_API_KEY}} diff --git a/.github/workflows/preview-docs.yml b/.github/workflows/preview-docs.yml index 81dbb37f..5366520f 100644 --- a/.github/workflows/preview-docs.yml +++ b/.github/workflows/preview-docs.yml @@ -20,6 +20,21 @@ jobs: python-version: 3.12 cache: true + - name: Generate overrides to use current branch if PR + if: github.event_name == 'pull_request' + run: | + pdm run tools/gen_overrides.py ${{github.head_ref}} > overrides.txt + echo "Generated overrides:" + cat overrides.txt + + - name: Relock PDM + if: github.event_name != 'pull_request' + run: pdm lock -d + + - name: Relock PDM (PR) + if: github.event_name == 'pull_request' + run: pdm lock -d --override overrides.txt + - name: Install dependencies run: pdm install diff --git a/chipflow_lib/pin_lock.py b/chipflow_lib/pin_lock.py index 97917c3a..4462725c 100644 --- a/chipflow_lib/pin_lock.py +++ b/chipflow_lib/pin_lock.py @@ -43,7 +43,7 @@ def allocate_pins(name: str, member: Dict[str, Any], pins: List[str], port_name: if member['type'] == 'interface' and 'annotations' in member \ and PIN_ANNOTATION_SCHEMA in member['annotations']: - logger.debug("matched PinSignature {sig}") + logger.debug("matched IOSignature {sig}") sig = member['annotations'][PIN_ANNOTATION_SCHEMA] width = sig['width'] options = sig['options'] @@ -62,7 +62,7 @@ def allocate_pins(name: str, member: Dict[str, Any], pins: List[str], port_name: logger.debug(f"{pin_map},{_map}") return pin_map, pins elif member['type'] == 'port': - logger.warning(f"Port '{name}' has no PinSignature, pin allocation likely to be wrong") + logger.warning(f"Port '{name}' has no IOSignature, pin allocation likely to be wrong") width = member['width'] pin_map[name] = {'pins': pins[0:width], 'direction': member['dir'], diff --git a/chipflow_lib/platforms/utils.py b/chipflow_lib/platforms/utils.py index 966c0edf..d54285e9 100644 --- a/chipflow_lib/platforms/utils.py +++ b/chipflow_lib/platforms/utils.py @@ -17,8 +17,8 @@ from .. import ChipFlowError, _ensure_chipflow_root, _get_cls_by_reference -__all__ = ['PIN_ANNOTATION_SCHEMA', 'PinSignature', - 'OutputPinSignature', 'InputPinSignature', 'BidirPinSignature', +__all__ = ['PIN_ANNOTATION_SCHEMA', 'IOSignature', + 'OutputIOSignature', 'InputIOSignature', 'BidirIOSignature', 'load_pinlock', "PACKAGE_DEFINITIONS", 'top_interfaces'] @@ -64,7 +64,7 @@ def as_json(self): # type: ignore PIN_ANNOTATION_SCHEMA = str(_chipflow_schema_uri("pin-annotation", 0)) -class PinSignature(wiring.Signature): +class IOSignature(wiring.Signature): """Amaranth Signtaure used to decorate wires that would usually be brought out onto a port on the package. @@ -115,19 +115,19 @@ def annotations(self, *args): def __repr__(self): opts = ', '.join(f"{k}={v}" for k, v in self._options.items()) - return f"PinSignature({self._direction}, {self._width}, {opts})" + return f"IOSignature({self._direction}, {self._width}, {opts})" -def OutputPinSignature(width, **kwargs): - return PinSignature(io.Direction.Output, width=width, **kwargs) +def OutputIOSignature(width, **kwargs): + return IOSignature(io.Direction.Output, width=width, **kwargs) -def InputPinSignature(width, **kwargs): - return PinSignature(io.Direction.Input, width=width, **kwargs) +def InputIOSignature(width, **kwargs): + return IOSignature(io.Direction.Input, width=width, **kwargs) -def BidirPinSignature(width, **kwargs): - return PinSignature(io.Direction.Bidir, width=width, **kwargs) +def BidirIOSignature(width, **kwargs): + return IOSignature(io.Direction.Bidir, width=width, **kwargs) Pin = Union[tuple, str] diff --git a/tests/fixtures/mock_top.py b/tests/fixtures/mock_top.py index 4339c9d7..27cfbff9 100644 --- a/tests/fixtures/mock_top.py +++ b/tests/fixtures/mock_top.py @@ -3,26 +3,26 @@ from amaranth.lib import wiring from amaranth.lib.wiring import In, Out -from chipflow_lib.platforms import InputPinSignature, OutputPinSignature, BidirPinSignature +from chipflow_lib.platforms import InputIOSignature, OutputIOSignature, BidirIOSignature __all__ = ["MockTop"] TestSignature1 = wiring.Signature({ - "a": In(InputPinSignature(1)), - "b": In(InputPinSignature(5)), - "c": Out(OutputPinSignature(1)), - "d": Out(OutputPinSignature(10)), - "e": In(BidirPinSignature(1)), - "f": In(BidirPinSignature(7)), + "a": In(InputIOSignature(1)), + "b": In(InputIOSignature(5)), + "c": Out(OutputIOSignature(1)), + "d": Out(OutputIOSignature(10)), + "e": In(BidirIOSignature(1)), + "f": In(BidirIOSignature(7)), }) TestSignature2 = wiring.Signature({ - "a": Out(OutputPinSignature(1)), - "b": Out(OutputPinSignature(5)), - "c": In(InputPinSignature(1)), - "d": In(InputPinSignature(10)), - "e": Out(BidirPinSignature(1)), - "f": Out(BidirPinSignature(7)), + "a": Out(OutputIOSignature(1)), + "b": Out(OutputIOSignature(5)), + "c": In(InputIOSignature(1)), + "d": In(InputIOSignature(10)), + "e": Out(BidirIOSignature(1)), + "f": Out(BidirIOSignature(7)), }) diff --git a/tests/test_utils.py b/tests/test_utils.py index e0f77280..c66428d1 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -7,7 +7,7 @@ from amaranth.lib import io -from chipflow_lib.platforms.utils import PinSignature, OutputPinSignature, InputPinSignature, BidirPinSignature, _PinAnnotation, _PinAnnotationModel +from chipflow_lib.platforms.utils import IOSignature, OutputIOSignature, InputIOSignature, BidirIOSignature, _PinAnnotation, _PinAnnotationModel from chipflow_lib.platforms.utils import PinList, _group_consecutive_items,_find_contiguous_sequence, _Side @@ -53,32 +53,32 @@ def test_find_contiguous_sequence(): def test_pin_signature(): - sig_bidir = PinSignature(io.Direction.Bidir, width=8) - assert isinstance(sig_bidir, PinSignature) + sig_bidir = IOSignature(io.Direction.Bidir, width=8) + assert isinstance(sig_bidir, IOSignature) assert sig_bidir._direction == io.Direction.Bidir assert sig_bidir._width == 8 assert "o" in sig_bidir.members assert "oe" in sig_bidir.members assert "i" in sig_bidir.members - sig_output = OutputPinSignature(width=4) - assert isinstance(sig_output, PinSignature) + sig_output = OutputIOSignature(width=4) + assert isinstance(sig_output, IOSignature) assert sig_output._direction == io.Direction.Output assert sig_output._width == 4 assert "o" in sig_output.members assert "oe" not in sig_output.members assert "i" not in sig_output.members - sig_input = InputPinSignature(width=2) - assert isinstance(sig_input, PinSignature) + sig_input = InputIOSignature(width=2) + assert isinstance(sig_input, IOSignature) assert sig_input._direction == io.Direction.Input assert sig_input._width == 2 assert "o" not in sig_input.members assert "oe" not in sig_output.members assert "i" in sig_input.members - sig_bidir_fn = BidirPinSignature(width=1) - assert isinstance(sig_bidir_fn, PinSignature) + sig_bidir_fn = BidirIOSignature(width=1) + assert isinstance(sig_bidir_fn, IOSignature) assert sig_bidir_fn._direction == io.Direction.Bidir assert sig_bidir_fn._width == 1 assert "o" in sig_bidir_fn.members diff --git a/tests/test_utils_additional.py b/tests/test_utils_additional.py index 8a95cbbd..538c104c 100644 --- a/tests/test_utils_additional.py +++ b/tests/test_utils_additional.py @@ -12,7 +12,7 @@ _PinAnnotationModel, _PinAnnotation, PIN_ANNOTATION_SCHEMA, - PinSignature, + IOSignature, _Side, _BasePackageDef, _BareDiePackageDef, @@ -69,12 +69,12 @@ def test_pin_annotation(self): self.assertEqual(json_data["options"], {}) -class TestPinSignature(unittest.TestCase): +class TestIOSignature(unittest.TestCase): def test_pin_signature_properties(self): - """Test PinSignature properties""" + """Test IOSignature properties""" # Create signature with options options = {"all_have_oe": True, "init": 0} - sig = PinSignature(io.Direction.Bidir, width=4, all_have_oe=True, init=0) + sig = IOSignature(io.Direction.Bidir, width=4, all_have_oe=True, init=0) # Test properties self.assertEqual(sig.direction, io.Direction.Bidir) @@ -83,15 +83,15 @@ def test_pin_signature_properties(self): # Test __repr__ - actual representation depends on Direction enum's representation repr_string = repr(sig) - self.assertIn("PinSignature", repr_string) + self.assertIn("IOSignature", repr_string) self.assertIn("4", repr_string) self.assertIn("all_have_oe=True", repr_string) self.assertIn("init=0", repr_string) def test_pin_signature_annotations(self): - """Test PinSignature annotations method""" + """Test IOSignature annotations method""" # Create signature - sig = PinSignature(io.Direction.Output, width=8, init=42) + sig = IOSignature(io.Direction.Output, width=8, init=42) # Create a mock object to pass to annotations mock_obj = object() diff --git a/tools/gen_overrides.py b/tools/gen_overrides.py new file mode 100644 index 00000000..62ea7bd8 --- /dev/null +++ b/tools/gen_overrides.py @@ -0,0 +1,54 @@ +# gen-overrides.py +# /// script +# requires-python = ">=3.10" +# dependencies = [ +# "pyproject-parser", +# "requirements-parser", +# ] +# /// +# SPDX-License-Identifier: BSD-2-Clause +import os +import subprocess +import sys +import urllib +from pathlib import Path + +from pyproject_parser import PyProject +from requirements.requirement import Requirement + + +rootdir = Path(os.environ["PDM_PROJECT_ROOT"]) + +def get_branch(repo_dir): + """Get the current git branch""" + return subprocess.check_output(['git', 'branch', '--show-current'], text=True).strip() + +def get_remote_branch(repo, branch): + return subprocess.call( + ['git', 'ls-remote', '--exit-code', '--heads', repo, f'refs/heads/{branch}'], + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) == 0 + +def gen_overrides(): + if len(sys.argv) > 1: + branch = sys.argv[1] + if branch.startswith("refs/heads/"): + branch = branch[11:] + else: + branch = get_branch(rootdir) + prj = PyProject.load(rootdir / "pyproject.toml") + reqs = prj.project['dependencies'] + git_reqs = [r for r in reqs if r.url and r.url.startswith('git+')] + for r in git_reqs: + parts = urllib.parse.urlparse(r.url, allow_fragments=True) + # remove any branches that might already be there + base = parts.path.rsplit(sep="@",maxsplit=1)[0] + clone_url = urllib.parse.urlunparse(parts._replace(path=base, scheme="https")) + if get_remote_branch(clone_url, branch): + path = f"{parts.path}@{branch}" + else: + path = parts.path + r.url = urllib.parse.urlunparse(parts._replace(path=path)) + print(str(r)) + +if __name__ == "__main__": + gen_overrides() diff --git a/tools/license_check.sh b/tools/license_check.sh new file mode 100755 index 00000000..4e700344 --- /dev/null +++ b/tools/license_check.sh @@ -0,0 +1,4 @@ +#!/bin/bash +docker run --platform=linux/amd64 -v ${PWD}:/src ghcr.io/google/addlicense -v -check -l BSD-2-Clause -c "ChipFlow" -s=only -ignore **/__init__.py **/*.py + +