Skip to content

Commit e7f6554

Browse files
committed
memory: restrict resources to wiring.Component objects.
Also, csr.Multiplexer now requires the signature of its memory map resources to contain a csr.Element.Signature member, named "element" and oriented as output.
1 parent 095b018 commit e7f6554

File tree

9 files changed

+371
-266
lines changed

9 files changed

+371
-266
lines changed

amaranth_soc/csr/bus.py

Lines changed: 86 additions & 92 deletions
Large diffs are not rendered by default.

amaranth_soc/csr/event.py

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,20 @@
66
from amaranth.lib.wiring import In, Out, flipped, connect
77
from amaranth.utils import ceil_log2
88

9-
from . import Element, Multiplexer
9+
from . import Multiplexer
10+
from .reg import Register, Field, FieldAction
1011
from .. import event
1112
from ..memory import MemoryMap
1213

1314

1415
__all__ = ["EventMonitor"]
1516

1617

18+
class _EventMaskRegister(Register, access="rw"):
19+
def __init__(self, width):
20+
super().__init__({"mask": Field(FieldAction, width, access="rw")})
21+
22+
1723
class EventMonitor(wiring.Component):
1824
"""Event monitor.
1925
@@ -54,15 +60,15 @@ def __init__(self, event_map, *, trigger="level", data_width, alignment=0, name=
5460
raise ValueError(f"Alignment must be a non-negative integer, not {alignment!r}")
5561

5662
self._monitor = event.Monitor(event_map, trigger=trigger)
57-
self._enable = Element(event_map.size, "rw")
58-
self._pending = Element(event_map.size, "rw")
63+
self._enable = _EventMaskRegister(event_map.size)
64+
self._pending = _EventMaskRegister(event_map.size)
5965

60-
elem_size = ceil(event_map.size / data_width)
61-
addr_width = 1 + max(ceil_log2(elem_size), alignment)
66+
reg_size = (event_map.size + data_width - 1) // data_width
67+
addr_width = 1 + max(ceil_log2(reg_size), alignment)
6268
memory_map = MemoryMap(addr_width=addr_width, data_width=data_width, alignment=alignment)
69+
memory_map.add_resource(self._enable, size=reg_size, name="enable")
70+
memory_map.add_resource(self._pending, size=reg_size, name="pending")
6371

64-
self._enable .add_to(memory_map, name="enable")
65-
self._pending.add_to(memory_map, name="pending")
6672
self._mux = Multiplexer(memory_map)
6773

6874
super().__init__({
@@ -81,12 +87,12 @@ def elaborate(self, platform):
8187
connect(m, flipped(self.src), self._monitor.src)
8288
connect(m, self.bus, self._mux.bus)
8389

84-
with m.If(self._enable.w_stb):
85-
m.d.sync += self._monitor.enable.eq(self._enable.w_data)
86-
m.d.comb += self._enable.r_data.eq(self._monitor.enable)
90+
with m.If(self._enable.element.w_stb):
91+
m.d.sync += self._monitor.enable.eq(self._enable.element.w_data)
92+
m.d.comb += self._enable.element.r_data.eq(self._monitor.enable)
8793

88-
with m.If(self._pending.w_stb):
89-
m.d.comb += self._monitor.clear.eq(self._pending.w_data)
90-
m.d.comb += self._pending.r_data.eq(self._monitor.pending)
94+
with m.If(self._pending.element.w_stb):
95+
m.d.comb += self._monitor.clear.eq(self._pending.element.w_data)
96+
m.d.comb += self._pending.element.r_data.eq(self._monitor.pending)
9197

9298
return m

amaranth_soc/csr/reg.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -872,20 +872,20 @@ def traverse_path(path, obj):
872872
register_map.freeze()
873873

874874
for register, path in register_map.flatten():
875-
elem_addr, assigned = traverse_path(path, register_addr)
876-
if assigned != path and elem_addr is not None:
875+
reg_addr, assigned = traverse_path(path, register_addr)
876+
if assigned != path and reg_addr is not None:
877877
raise TypeError(f"Register address assignment for the cluster {tuple(assigned)} "
878-
f"must be a dict or None, not {elem_addr!r}")
878+
f"must be a dict or None, not {reg_addr!r}")
879879

880-
elem_alignment, assigned = traverse_path(path, register_alignment)
881-
if assigned != path and elem_alignment is not None:
880+
reg_alignment, assigned = traverse_path(path, register_alignment)
881+
if assigned != path and reg_alignment is not None:
882882
raise TypeError(f"Register alignment assignment for the cluster {tuple(assigned)} "
883-
f"must be a dict or None, not {elem_alignment!r}")
883+
f"must be a dict or None, not {reg_alignment!r}")
884884

885-
elem_size = (register.element.width + data_width - 1) // data_width
886-
elem_name = "__".join(path)
887-
memory_map.add_resource(register.element, name=elem_name, size=elem_size,
888-
addr=elem_addr, alignment=elem_alignment)
885+
reg_size = (register.element.width + data_width - 1) // data_width
886+
reg_name = "__".join(path)
887+
memory_map.add_resource(register, name=reg_name, size=reg_size, addr=reg_addr,
888+
alignment=reg_alignment)
889889

890890
self._map = register_map
891891
self._mux = Multiplexer(memory_map)

amaranth_soc/memory.py

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import bisect
22

3+
from amaranth.lib import wiring
34
from amaranth.utils import bits_for
45

56

@@ -50,12 +51,12 @@ def items(self):
5051
class ResourceInfo:
5152
"""Resource metadata.
5253
53-
A wrapper class for resource objects, with their assigned path and address range.
54+
A description of a memory map resource with its assigned path and address range.
5455
5556
Parameters
5657
----------
57-
resource : object
58-
Arbitrary object representing a resource. See :meth:`MemoryMap.add_resource` for details.
58+
resource : :class:`wiring.Component`
59+
A resource located in the memory map. See :meth:`MemoryMap.add_resource` for details.
5960
path : iter(str)
6061
Path of the resource. It is composed of the names of each window sitting between
6162
the resource and the memory map from which this :class:`ResourceInfo` was obtained.
@@ -263,8 +264,8 @@ def add_resource(self, resource, *, name, size, addr=None, alignment=None):
263264
264265
Arguments
265266
---------
266-
resource : object
267-
Arbitrary object representing a resource.
267+
resource : :class:`wiring.Component`
268+
The resource to be added.
268269
name : str
269270
Name of the resource. It must not collide with the name of other resources or windows
270271
present in this memory map.
@@ -284,18 +285,25 @@ def add_resource(self, resource, *, name, size, addr=None, alignment=None):
284285
285286
Exceptions
286287
----------
287-
Raises :exn:`ValueError` if one of the following occurs:
288-
289-
- this memory map is frozen;
290-
- the requested address and size, after alignment, would overlap with any resources or
291-
windows that have already been added, or would be out of bounds;
292-
- the resource has already been added to this memory map;
293-
- the name of the resource is already present in the namespace of this memory map;
288+
:exc:`ValueError`
289+
If the memory map is frozen.
290+
:exc:`TypeError`
291+
If the resource is not a :class:`wiring.Component`.
292+
:exc:`ValueError`
293+
If the requested address and size, after alignment, would overlap with any resources or
294+
windows that have already been added, or would be out of bounds.
295+
:exc:`ValueError`
296+
If the resource has already been added to this memory map.
297+
:exc:`ValueError`
298+
If the name of the resource is already present in the namespace of this memory map.
294299
"""
295300
if self._frozen:
296301
raise ValueError("Memory map has been frozen. Cannot add resource {!r}"
297302
.format(resource))
298303

304+
if not isinstance(resource, wiring.Component):
305+
raise TypeError(f"Resource must be a wiring.Component, not {resource!r}")
306+
299307
if id(resource) in self._resources:
300308
_, _, addr_range = self._resources[id(resource)]
301309
raise ValueError("Resource {!r} is already added at address range {:#x}..{:#x}"

0 commit comments

Comments
 (0)