From 5e5d6f8a0b1bf9de496f4501f7e595119cd79c2b Mon Sep 17 00:00:00 2001 From: Rob Taylor Date: Tue, 4 Mar 2025 22:27:03 +0000 Subject: [PATCH 1/3] Enable a a bidir port to have either one output enable, or one for each wire --- chipflow_lib/pin_lock.py | 4 +++- chipflow_lib/platforms/silicon.py | 14 ++++++++++++-- chipflow_lib/platforms/utils.py | 22 +++++++++++++++++----- chipflow_lib/steps/silicon.py | 7 +++---- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/chipflow_lib/pin_lock.py b/chipflow_lib/pin_lock.py index 934f7ad4..a88b961a 100644 --- a/chipflow_lib/pin_lock.py +++ b/chipflow_lib/pin_lock.py @@ -45,9 +45,11 @@ def allocate_pins(name: str, member: Dict[str, Any], pins: List[str]) -> Tuple[D name = name sig = member['annotations'][PIN_ANNOTATION_SCHEMA] width = sig['width'] + options = sig['options'] pin_map[name] = {'pins': pins[0:width], 'direction': sig['direction'], - 'type': 'io'} + 'type': 'io', + 'options': options} logger.debug(f"added '{name}':{pin_map[name]} to pin_map") return pin_map, pins[width:] elif member['type'] == 'interface': diff --git a/chipflow_lib/platforms/silicon.py b/chipflow_lib/platforms/silicon.py index 1a32624f..bec848ba 100644 --- a/chipflow_lib/platforms/silicon.py +++ b/chipflow_lib/platforms/silicon.py @@ -70,13 +70,19 @@ def __init__(self, invert: bool = False): self._direction = io.Direction(port.direction) self._invert = invert + self._options = port.options self._i = self._o = self._oe = Signal(1) if self._direction in (io.Direction.Input, io.Direction.Bidir): self._i = Signal(port.width, name=f"{component}_{name}__i") if self._direction in (io.Direction.Output, io.Direction.Bidir): self._o = Signal(port.width, name=f"{component}_{name}__o") - self._oe = Signal(1, name=f"{component}_{name}__oe") + if self._direction is io.Direction.Bidir: + if "all_have_oe" in self._options and self._options["all_have_oe"]: + self._oe = Signal(port.width, name=f"{component}_{name}__oe") + else: + self._oe = Signal(1, name=f"{component}_{name}__oe") + self._pins = port.pins logger.debug(f"Created SiliconPlatformPort {name}, width={len(port.pins)},dir{self._direction}") @@ -120,7 +126,11 @@ def __len__(self): assert len(self._o) == len(self._oe) return len(self._o) if self._direction is io.Direction.Bidir: - assert len(self._i) == len(self._o) == len(self._oe) + assert len(self._i) == len(self._o) + if self._options["all_have_oe"]: + assert len(self.o) == len(self._oe) + else: + assert len(self._oe) == 1 return len(self._i) assert False # :nocov: diff --git a/chipflow_lib/platforms/utils.py b/chipflow_lib/platforms/utils.py index c8bcbe6b..02502af5 100644 --- a/chipflow_lib/platforms/utils.py +++ b/chipflow_lib/platforms/utils.py @@ -33,6 +33,7 @@ class _PinAnnotationModel(BaseModel): model_config = ConfigDict(use_enum_values=True) direction: io.Direction width: int + options: dict = {} @classmethod def _annotation_schema(cls): @@ -65,10 +66,15 @@ def as_json(self): # type: ignore class PinSignature(wiring.Signature): """Amaranth Signtaure used to decorate wires that would - usually be brought out onto a pin on the package. + usually be brought out onto a port on the package. + + direction: Input, Output or Bidir + width: width of port + all_have_oe: For Bidir ports, should Output Enable be per wire or for the whole port + init: a :ref:`const-castable object ` for the initial values of the port """ - def __init__(self, direction, width=1, init=None): + def __init__(self, direction: io.Direction, width: int = 1, all_have_oe: bool = False, init = None): self._direction = direction self._width = width self._init = init @@ -76,7 +82,7 @@ def __init__(self, direction, width=1, init=None): case io.Direction.Bidir: sig = { "o": Out(width), - "oe": Out(1), + "oe": Out(width if all_have_oe else 1), "i": In(width) } case io.Direction.Input: @@ -85,16 +91,21 @@ def __init__(self, direction, width=1, init=None): sig = {"o": Out(width)} case _: assert False + self._options = { + "all_have_oe": all_have_oe, + "init": init, + } super().__init__(sig) def annotations(self, *args): annotations = wiring.Signature.annotations(self, *args) - pin_annotation = _PinAnnotation(direction=self._direction, width=self._width) + pin_annotation = _PinAnnotation(direction=self._direction, width=self._width, options=self._options) return annotations + (pin_annotation,) def __repr__(self): - return f"PinSignature({self._direction}, {self._width})" + opts = ', '.join(f"{k}={v}" for k, v in self._options.items()) + return f"PinSignature({self._direction}, {self._width}, {opts})" def OutputPinSignature(width, **kwargs): @@ -297,6 +308,7 @@ class Port(pydantic.BaseModel): type: str pins: List[str] direction: Optional[str] = None + options: Optional[dict] = None @property def width(self): diff --git a/chipflow_lib/steps/silicon.py b/chipflow_lib/steps/silicon.py index a9031bfa..7fdf6f1b 100644 --- a/chipflow_lib/steps/silicon.py +++ b/chipflow_lib/steps/silicon.py @@ -12,7 +12,6 @@ import time import dotenv - from amaranth import * from .. import ChipFlowError @@ -124,13 +123,13 @@ def submit(self, rtlil_path, *, dry_run=False): pads = {} for iface, port in self.platform._ports.items(): width = len(port.pins) - print(f"iface={iface}, port={port}, dir={port.direction}, width={width}") + logger.debug(f"iface={iface}, port={port}, dir={port.direction}, width={width}") if width > 1: for i in range(width): padname = f"{iface}{i}" - print(f"padname={padname}, port={port}, loc={port.pins[i:i+1]}, " + logger.debug(f"padname={padname}, port={port}, loc={port.pins[i]}, " f"dir={port.direction}, width={width}") - pads[padname] = {'loc': port.pins[i:i+1], 'dir': port.direction} + pads[padname] = {'loc': port.pins[i], 'dir': port.direction.value} config = { "dependency_versions": dep_versions, From cf82bb60a8b91bdb429cc203f8e459acb4031df2 Mon Sep 17 00:00:00 2001 From: Rob Taylor Date: Thu, 6 Mar 2025 23:01:53 +0000 Subject: [PATCH 2/3] Force load_dotenv to use cwd, and move to before the checks --- chipflow_lib/steps/silicon.py | 2 +- tests/test_silicon_step.py | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/chipflow_lib/steps/silicon.py b/chipflow_lib/steps/silicon.py index 7fdf6f1b..888a49b7 100644 --- a/chipflow_lib/steps/silicon.py +++ b/chipflow_lib/steps/silicon.py @@ -64,6 +64,7 @@ def build_cli_parser(self, parser): def run_cli(self, args): if args.action == "submit" and not args.dry_run: + dotenv.load_dotenv(dotenv_path=dotenv.find_dotenv(usecwd=True)) if self.project_name is None: raise ChipFlowError( "Key `chipflow.project_id` is not defined in chipflow.toml; " @@ -88,7 +89,6 @@ def prepare(self): def submit(self, rtlil_path, *, dry_run=False): """Submit the design to the ChipFlow cloud builder. """ - dotenv.load_dotenv() git_head = subprocess.check_output( ["git", "-C", os.environ["CHIPFLOW_ROOT"], "rev-parse", "HEAD"], diff --git a/tests/test_silicon_step.py b/tests/test_silicon_step.py index f3ea5f37..8c6a1295 100644 --- a/tests/test_silicon_step.py +++ b/tests/test_silicon_step.py @@ -41,9 +41,8 @@ def setUp(self): os.environ["CHIPFLOW_API_KEY_ID"] = "keyid" os.environ["CHIPFLOW_API_KEY_SECRET"] = "keysecret" - @patch('dotenv.load_dotenv') @patch('requests.post', side_effect=mocked_requests_post) - def test_submit_happy_path(self, mock_requests_post, mock_dotenv): + def test_submit_happy_path(self, mock_requests_post): customer_config = f"{current_dir}/fixtures/mock.toml" with open(customer_config, "rb") as f: config_dict = tomli.load(f) @@ -87,5 +86,3 @@ def test_submit_happy_path(self, mock_requests_post, mock_dotenv): } } assert rtlil == b"fake-rtlil", "The RTL file was passed through." - - assert mock_dotenv.called From 873c5b12d702e734e02608249acc5cdc5d0c00a2 Mon Sep 17 00:00:00 2001 From: Rob Taylor Date: Tue, 4 Mar 2025 18:59:25 +0000 Subject: [PATCH 3/3] Send type in submit for old api support --- chipflow_lib/steps/silicon.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/chipflow_lib/steps/silicon.py b/chipflow_lib/steps/silicon.py index 888a49b7..2f2b56e7 100644 --- a/chipflow_lib/steps/silicon.py +++ b/chipflow_lib/steps/silicon.py @@ -31,13 +31,15 @@ def elaborate(self, platform: SiliconPlatform): platform.instantiate_ports(m) # heartbeat led (to confirm clock/reset alive) - if ("config" in self._config["chipflow"]["silicon"] and + if ("debug" in self._config["chipflow"]["silicon"] and self._config["chipflow"]["silicon"]["debug"]["heartbeat"]): heartbeat_ctr = Signal(23) m.d.sync += heartbeat_ctr.eq(heartbeat_ctr + 1) m.d.comb += platform.request("heartbeat").o.eq(heartbeat_ctr[-1]) top, interfaces = top_interfaces(self._config) + logger.debug(f"SiliconTop top = {top}, interfaces={interfaces}") + for n, t in top.items(): setattr(m.submodules, n, t) @@ -129,7 +131,14 @@ def submit(self, rtlil_path, *, dry_run=False): padname = f"{iface}{i}" logger.debug(f"padname={padname}, port={port}, loc={port.pins[i]}, " f"dir={port.direction}, width={width}") - pads[padname] = {'loc': port.pins[i], 'dir': port.direction.value} + pads[padname] = {'loc': port.pins[i], 'type': port.direction.value} + else: + padname = f"{iface}" + + 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} + config = { "dependency_versions": dep_versions,