Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
19 changes: 19 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Basic .gitattributes for a python repo.

# Source files
# ============
*.py text diff=python eol=lf whitespace=trailing-space,space-before-tab,tab-in-indent,tabwidth=4

# Binary files
# ============
*.db binary
*.p binary
*.pkl binary
*.pickle binary
*.pyc binary export-ignore
*.pyo binary export-ignore
*.pyd binary

# Jupyter notebook
*.ipynb text eol=lf

2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ __pycache__/
.doit.db

docs/_build
.cache

13 changes: 6 additions & 7 deletions chipflow_lib/config_models.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# SPDX-License-Identifier: BSD-2-Clause
import enum
import re
from typing import Dict, List, Optional, Union, Literal, Any
from typing import Dict, Optional, Literal, Any

from pydantic import BaseModel, Field, model_validator, ValidationInfo, field_validator
from pydantic import BaseModel, model_validator, ValidationInfo, field_validator

from .platforms.utils import Process

Expand All @@ -19,7 +18,7 @@ def validate_loc_format(self):
if not re.match(r"^[NSWE]?[0-9]+$", self.loc):
raise ValueError(f"Invalid location format: {self.loc}, expected format: [NSWE]?[0-9]+")
return self

@classmethod
def validate_pad_dict(cls, v: dict, info: ValidationInfo):
"""Custom validation for pad dicts from TOML that may not have all fields."""
Expand All @@ -28,11 +27,11 @@ def validate_pad_dict(cls, v: dict, info: ValidationInfo):
if 'loc' in v and 'type' not in v:
if info.field_name == 'power':
v['type'] = 'power'

# Map legacy 'clk' type to 'clock' to match our enum
if 'type' in v and v['type'] == 'clk':
v['type'] = 'clock'

return v
return v

Expand All @@ -44,7 +43,7 @@ class SiliconConfig(BaseModel):
pads: Dict[str, PadConfig] = {}
power: Dict[str, PadConfig] = {}
debug: Optional[Dict[str, bool]] = None

@field_validator('pads', 'power', mode='before')
@classmethod
def validate_pad_dicts(cls, v, info: ValidationInfo):
Expand Down
7 changes: 3 additions & 4 deletions chipflow_lib/pin_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from chipflow_lib import _parse_config, ChipFlowError
from chipflow_lib.platforms import PACKAGE_DEFINITIONS, PIN_ANNOTATION_SCHEMA, top_interfaces
from chipflow_lib.platforms.utils import LockFile, Package, PortMap, Port, Process
from chipflow_lib.platforms.utils import LockFile, Package, PortMap, Port
from chipflow_lib.config_models import Config

# logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
Expand Down Expand Up @@ -79,11 +79,10 @@ def allocate_pins(name: str, member: Dict[str, Any], pins: List[str], port_name:
def lock_pins() -> None:
# Get the config as dict for backward compatibility with top_interfaces
config_dict = _parse_config()

# Parse with Pydantic for type checking and strong typing
from chipflow_lib.config_models import Config
config_model = Config.model_validate(config_dict)

used_pins = set()
oldlock = None

Expand Down
6 changes: 3 additions & 3 deletions chipflow_lib/platforms/silicon.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

from amaranth.lib import wiring, io
from amaranth.lib.cdc import FFSynchronizer
from amaranth.lib.wiring import Component, In, PureInterface, flipped, connect
from amaranth.lib.wiring import Component, In, PureInterface

from amaranth.back import rtlil
from amaranth.hdl import Fragment
Expand Down Expand Up @@ -74,12 +74,12 @@ def __init__(self,
self._invert = invert
self._options = port.options
self._pins = port.pins

# Initialize signal attributes to None
self._i = None
self._o = None
self._oe = None

# Create signals based on direction
if self._direction in (io.Direction.Input, io.Direction.Bidir):
self._i = Signal(port.width, name=f"{component}_{name}__i")
Expand Down
2 changes: 1 addition & 1 deletion chipflow_lib/steps/silicon.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def submit(self, rtlil_path, *, dry_run=False):
logger.debug(f"padname={padname}, port={port}, loc={port.pins[0]}, "
f"dir={port.direction}, width={width}")
pads[padname] = {'loc': port.pins[0], 'type': port.direction.value}

# Use the Pydantic models to access configuration data
silicon_model = self.config_model.chipflow.silicon
config = {
Expand Down
276 changes: 147 additions & 129 deletions pdm.lock

Large diffs are not rendered by default.

11 changes: 8 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,15 @@ reportMissingImports = false
reportUnboundVariable = false

[tool.ruff]
include = ["pyproject.toml", "**/*.py", "chipflow.toml"]
include = [
"chipflow_lib/**/*.py",
"tests/**.py",
"chipflow.toml",
"pyproject.toml"
]

[tool.ruff.lint]
select = ["E4", "E7", "E9", "F", "W291", "W293"]
ignore = ['F403', 'F405']

[tool.pdm.version]
Expand All @@ -68,8 +74,7 @@ test-silicon.cmd = "pytest tests/test_silicon_platform.py tests/test_silicon_pla

[dependency-groups]
lint = [
"ruff",
"pytest-cov",
"ruff>=0.9.2",
]
test = [
"pytest>=7.2.0",
Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/mock_top.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,5 @@ def elaborate(self, platform):
m = Module()
for inpin, outpin in zip(self.test1.members, self.test2.members):
m.d.comb += inpin.eq(outpin)

return m
26 changes: 13 additions & 13 deletions tests/test_buffers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import unittest
from unittest import mock

from amaranth import Module, Signal
from amaranth import Module
from amaranth.lib import io

# We'll need to mock SiliconPlatformPort instead of using the real one
Expand All @@ -14,49 +14,49 @@ class TestBuffers(unittest.TestCase):
def test_io_buffer_mocked(self, mock_ffbuffer, mock_iobuffer):
"""Test that IOBuffer can be imported and mocked"""
from chipflow_lib.platforms.silicon import IOBuffer

# Verify that the mock is working
self.assertEqual(IOBuffer, mock_iobuffer)

# Create a mock port
port = mock.Mock()
port.invert = False

# Create a mock for the IOBuffer elaborate method
module = Module()
mock_iobuffer.return_value.elaborate.return_value = module

# Create an IOBuffer instance
buffer = IOBuffer(io.Direction.Input, port)

# Elaborate the buffer
result = buffer.elaborate(None)

# Verify the result
self.assertEqual(result, module)
mock_iobuffer.return_value.elaborate.assert_called_once()

def test_ff_buffer_mocked(self, mock_ffbuffer, mock_iobuffer):
"""Test that FFBuffer can be imported and mocked"""
from chipflow_lib.platforms.silicon import FFBuffer

# Verify that the mock is working
self.assertEqual(FFBuffer, mock_ffbuffer)

# Create a mock port
port = mock.Mock()
port.invert = False

# Create a mock for the FFBuffer elaborate method
module = Module()
mock_ffbuffer.return_value.elaborate.return_value = module

# Create an FFBuffer instance
buffer = FFBuffer(io.Direction.Input, port, i_domain="sync", o_domain="sync")

# Elaborate the buffer
result = buffer.elaborate(None)

# Verify the result
self.assertEqual(result, module)
mock_ffbuffer.return_value.elaborate.assert_called_once()
Loading
Loading