Skip to content

Commit e10875b

Browse files
authored
RFC #40: Arbitrary Memory shapes
2 parents e019bdb + 43ea961 commit e10875b

File tree

1 file changed

+83
-0
lines changed

1 file changed

+83
-0
lines changed

text/0040-arbitrary-memory-shape.md

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
- Start Date: 2024-01-22
2+
- RFC PR: [amaranth-lang/rfcs#40](https://github.com/amaranth-lang/rfcs/pull/40)
3+
- Amaranth Issue: [amaranth-lang/amaranth#1048](https://github.com/amaranth-lang/amaranth/issues/1048)
4+
5+
# Arbitrary `Memory` shapes
6+
7+
## Summary
8+
[summary]: #summary
9+
10+
Extend `Memory` to support arbitrary element shapes.
11+
12+
## Motivation
13+
[motivation]: #motivation
14+
15+
`Memory` currently only supports plain unsigned elements, with the width set by the `width` argument.
16+
Extending this to allow arbitrary shapes eliminates the need for manual conversion when used to store signed data and value-castables.
17+
18+
## Guide-level explanation
19+
[guide-level-explanation]: #guide-level-explanation
20+
21+
The `width` argument to `Memory()` is replaced with `shape`, accepting anything that is `ShapeLike`.
22+
Since a plain bit width is `ShapeLike`, this is a direct superset of existing functionality.
23+
24+
If `shape` is shape-castable, each element passed to the `init` argument is passed through `shape.const()`.
25+
26+
Example:
27+
```python
28+
RGB = StructLayout({"r": 8, "g": 8, "b": 8})
29+
30+
palette = Memory(shape = RGB, depth = 16, init = [
31+
{"r": 0, "g": 0, "b": 0},
32+
{"r": 255, "g": 0, "b": 0},
33+
# ...
34+
])
35+
```
36+
37+
## Reference-level explanation
38+
[reference-level-explanation]: #reference-level-explanation
39+
40+
`Memory.__init__()` gets a new `shape` argument, accepting any `ShapeLike`.
41+
42+
The `width` argument to `Memory.__init__()` deprecated and removed in a later Amaranth version. Passing both `width` and `shape` is an error.
43+
44+
The `Memory.shape` attribute is added.
45+
46+
The `Memory.width` attribute is made a read-only wrapper for `Shape.cast(self.shape).width`.
47+
48+
The `Memory.depth` attribute is made read-only.
49+
50+
`ReadPort.data` and `WritePort.data` are updated to be `Signal(memory.shape)`.
51+
52+
`WritePort.__init__()` raises an exception if `granularity` is specified and `shape` is not an unsigned `Shape`.
53+
54+
`DummyPort.__init__()` gets a new `data_shape` argument. `data_width` is deprecated and removed in a later Amaranth version.
55+
56+
## Drawbacks
57+
[drawbacks]: #drawbacks
58+
59+
Churn.
60+
61+
## Rationale and alternatives
62+
[rationale-and-alternatives]: #rationale-and-alternatives
63+
64+
- This could also be accomplished by adding a wrapper around `Memory`.
65+
- A wrapper would result in more code to maintain than simply updating `Memory`, since both the memory object itself and the port objects would have to be wrapped.
66+
67+
## Prior art
68+
[prior-art]: #prior-art
69+
70+
Being able to make a `Memory` with an arbitrary element shape is analogous to being able to make an array with an arbitrary element type in any high level programming language.
71+
72+
## Unresolved questions
73+
[unresolved-questions]: #unresolved-questions
74+
75+
None.
76+
77+
## Future possibilities
78+
[future-possibilities]: #future-possibilities
79+
80+
- Once `Memory` is extended to support arbitrary shapes, it is natural that higher level constructs building on `Memory` like FIFOs gets the same treatment.
81+
82+
- `granularity` could later be allowed to be used with other kinds of shapes.
83+
- This is desirable for e.g. `lib.data.ArrayLayout`, but is not currently possible since `Memory` lives in `hdl.mem`, and `hdl` can't depend on `lib`.

0 commit comments

Comments
 (0)