Skip to content

Add an RFC for PortLike.with_direction. #79

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
66 changes: 66 additions & 0 deletions text/0079-port-with-direction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
- Start Date: 2025-06-02
- RFC PR: [amaranth-lang/rfcs#79](https://github.com/amaranth-lang/rfcs/pull/79)
- Amaranth Issue: [amaranth-lang/amaranth#0000](https://github.com/amaranth-lang/amaranth/issues/0000)

# Add `PortLike.with_direction`

## Summary
[summary]: #summary

Add a `with_direction` method to `lib.io.PortLike`, allowing for "downcasting" a bidirectional port to an input port or an output port.

## Motivation
[motivation]: #motivation

[RFC 55](https://amaranth-lang.org/rfcs/0055-lib-io.html) has made way for a variety of generic and reusable I/O components. Many such components can be parametrized by the "signature" of I/O ports used, including their directionality. One such motivating example is Glasgow's `IOStreamer`.

It is often convenient to treat a bidirectional port as an input-only port, or an output-only port. `lib.io` already allows such usage by instantiating a `*Buffer` with a requested direction. However, for generic components, it's oftern convenient to determine requested buffer direction by introspecting the provided port — in such case, we need some means to explicitly "downcast" the port before providing it to the component.

## Guide-level explanation
[guide-level-explanation]: #guide-level-explanation

Given a `PortLike` with a direction of `Direction.Bidir`, you can use the `with_direction` method to obtain an input-only or output-only version of it:

```
port_io = platform.request("io0", dir="-")
assert port_io.direction == Direction.Bidir
port_i = port_io.with_direction("i")
assert port_i.direction == Direction.Input
```

## Reference-level explanation
[reference-level-explanation]: #reference-level-explanation

A new method is added to `PortLike` and its implementations:

- `with_direction(self, direction: Direction) -> PortLike`: returns a new `PortLike` equivalent to this one, but with a limitted direction
- if the `direction` provided is the same as the port's direction, the returned `PortLike` is fully equivalent to `self`
- if the `direction` is `Direction.Input` or `Direction.Output` and `self.direction is Direction.Bidir`, the returned `PortLike` has the given direction
- any other combination of `direction` and `self.direction` is an error

## Drawbacks
[drawbacks]: #drawbacks

This adds a new required method to implement on a `PortLike`, and is thus a breaking change for users implementing their own `PortLike`s.

## Rationale and alternatives
[rationale-and-alternatives]: #rationale-and-alternatives

The only obvious alternative to this RFC is providing the information to the generic component out-of-band. However, this is inconvenient, particularly when groups of ports are involved.

We can have the usual bikeshedding about the name.

## Prior art
[prior-art]: #prior-art

Most languages allow using an `inout` as an `input` or `output`.

## Unresolved questions
[unresolved-questions]: #unresolved-questions

None.

## Future possibilities
[future-possibilities]: #future-possibilities

None.