Skip to content

Commit 4cd6f94

Browse files
committed
Add annotations for memory maps, wishbone and CSR primitives.
1 parent 2f2ad5c commit 4cd6f94

File tree

6 files changed

+856
-66
lines changed

6 files changed

+856
-66
lines changed

amaranth_soc/csr/bus.py

+175-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
from collections import defaultdict
22
from amaranth import *
3-
from amaranth.lib import enum, wiring
3+
from amaranth.lib import enum, wiring, meta
44
from amaranth.lib.wiring import In, Out, flipped
55
from amaranth.utils import ceil_log2
66

77
from ..memory import MemoryMap
88

99

10-
__all__ = ["Element", "Signature", "Interface", "Decoder", "Multiplexer"]
10+
__all__ = ["Element", "Signature", "Annotation", "Interface", "Decoder", "Multiplexer"]
1111

1212

1313
class Element(wiring.PureInterface):
@@ -113,6 +113,32 @@ def create(self, *, path=None, src_loc_at=0):
113113
"""
114114
return Element(self.width, self.access, path=path, src_loc_at=1 + src_loc_at)
115115

116+
def annotations(self, element, /):
117+
"""Get annotations of a compatible CSR element.
118+
119+
Parameters
120+
----------
121+
element : :class:`Element`
122+
A CSR element compatible with this signature.
123+
124+
Returns
125+
-------
126+
iterator of :class:`meta.Annotation`
127+
Annotations attached to ``element``.
128+
129+
Raises
130+
------
131+
:exc:`TypeError`
132+
If ``element`` is not an :class:`Element` object.
133+
:exc:`ValueError`
134+
If ``element.signature`` is not equal to ``self``.
135+
"""
136+
if not isinstance(element, Element):
137+
raise TypeError(f"Element must be a csr.Element object, not {element!r}")
138+
if element.signature != self:
139+
raise ValueError(f"Element signature is not equal to this signature")
140+
return (*super().annotations(element), Element.Annotation(element.signature))
141+
116142
def __eq__(self, other):
117143
"""Compare signatures.
118144
@@ -125,6 +151,64 @@ def __eq__(self, other):
125151
def __repr__(self):
126152
return f"csr.Element.Signature({self.members!r})"
127153

154+
class Annotation(meta.Annotation):
155+
schema = {
156+
"$schema": "https://json-schema.org/draft/2020-12/schema",
157+
"$id": "https://amaranth-lang.org/schema/amaranth-soc/0.1/csr/element.json",
158+
"type": "object",
159+
"properties": {
160+
"width": {
161+
"type": "integer",
162+
"minimum": 0,
163+
},
164+
"access": {
165+
"enum": ["r", "w", "rw"],
166+
},
167+
},
168+
"additionalProperties": False,
169+
"required": [
170+
"width",
171+
"access",
172+
],
173+
}
174+
175+
"""Peripheral-side CSR signature annotation.
176+
177+
Parameters
178+
----------
179+
origin : :class:`Element.Signature`
180+
The signature described by this annotation instance.
181+
182+
Raises
183+
------
184+
:exc:`TypeError`
185+
If ``origin`` is not a :class:`Element.Signature`.
186+
"""
187+
def __init__(self, origin):
188+
if not isinstance(origin, Element.Signature):
189+
raise TypeError(f"Origin must be a csr.Element.Signature object, not {origin!r}")
190+
self._origin = origin
191+
192+
@property
193+
def origin(self):
194+
return self._origin
195+
196+
def as_json(self):
197+
"""Translate to JSON.
198+
199+
Returns
200+
-------
201+
:class:`dict`
202+
A JSON representation of :attr:`~Element.Annotation.origin`, describing its width
203+
and access mode.
204+
"""
205+
instance = {
206+
"width": self.origin.width,
207+
"access": self.origin.access.value,
208+
}
209+
self.validate(instance)
210+
return instance
211+
128212
"""Peripheral-side CSR interface.
129213
130214
A low-level interface to a single atomically readable and writable register in a peripheral.
@@ -244,6 +328,35 @@ def create(self, *, path=None, src_loc_at=0):
244328
return Interface(addr_width=self.addr_width, data_width=self.data_width,
245329
path=path, src_loc_at=1 + src_loc_at)
246330

331+
def annotations(self, interface, /):
332+
"""Get annotations of a compatible CSR bus interface.
333+
334+
Parameters
335+
----------
336+
interface : :class:`Interface`
337+
A CSR bus interface compatible with this signature.
338+
339+
Returns
340+
-------
341+
iterator of :class:`meta.Annotation`
342+
Annotations attached to ``interface``.
343+
344+
Raises
345+
------
346+
:exc:`TypeError`
347+
If ``interface`` is not an :class:`Interface` object.
348+
:exc:`ValueError`
349+
If ``interface.signature`` is not equal to ``self``.
350+
"""
351+
if not isinstance(interface, Interface):
352+
raise TypeError(f"Interface must be a csr.Interface object, not {interface!r}")
353+
if interface.signature != self:
354+
raise ValueError(f"Interface signature is not equal to this signature")
355+
annotations = [*super().annotations(interface), Annotation(interface.signature)]
356+
if interface._memory_map is not None:
357+
annotations.append(interface._memory_map.annotation)
358+
return annotations
359+
247360
def __eq__(self, other):
248361
"""Compare signatures.
249362
@@ -257,6 +370,66 @@ def __repr__(self):
257370
return f"csr.Signature({self.members!r})"
258371

259372

373+
class Annotation(meta.Annotation):
374+
schema = {
375+
"$schema": "https://json-schema.org/draft/2020-12/schema",
376+
"$id": "https://amaranth-lang.org/schema/amaranth-soc/0.1/csr/bus.json",
377+
"type": "object",
378+
"properties": {
379+
"addr_width": {
380+
"type": "integer",
381+
"minimum": 0,
382+
},
383+
"data_width": {
384+
"type": "integer",
385+
"minimum": 0,
386+
},
387+
},
388+
"additionalProperties": False,
389+
"required": [
390+
"addr_width",
391+
"data_width",
392+
],
393+
}
394+
395+
"""CPU-side CSR signature annotation.
396+
397+
Parameters
398+
----------
399+
origin : :class:`Signature`
400+
The signature described by this annotation instance.
401+
402+
Raises
403+
------
404+
:exc:`TypeError`
405+
If ``origin`` is not a :class:`Signature`.
406+
"""
407+
def __init__(self, origin):
408+
if not isinstance(origin, Signature):
409+
raise TypeError(f"Origin must be a csr.Signature object, not {origin!r}")
410+
self._origin = origin
411+
412+
@property
413+
def origin(self):
414+
return self._origin
415+
416+
def as_json(self):
417+
"""Translate to JSON.
418+
419+
Returns
420+
-------
421+
:class:`dict`
422+
A JSON representation of :attr:`~Annotation.origin`, describing its address width
423+
and data width.
424+
"""
425+
instance = {
426+
"addr_width": self.origin.addr_width,
427+
"data_width": self.origin.data_width,
428+
}
429+
self.validate(instance)
430+
return instance
431+
432+
260433
class Interface(wiring.PureInterface):
261434
"""CPU-side CSR interface.
262435

0 commit comments

Comments
 (0)