Skip to content

Commit

Permalink
Add annotations for memory maps, wishbone and CSR primitives.
Browse files Browse the repository at this point in the history
  • Loading branch information
jfng committed Jan 19, 2024
1 parent 2f2ad5c commit 4cd6f94
Show file tree
Hide file tree
Showing 6 changed files with 856 additions and 66 deletions.
177 changes: 175 additions & 2 deletions amaranth_soc/csr/bus.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from collections import defaultdict
from amaranth import *
from amaranth.lib import enum, wiring
from amaranth.lib import enum, wiring, meta
from amaranth.lib.wiring import In, Out, flipped
from amaranth.utils import ceil_log2

from ..memory import MemoryMap


__all__ = ["Element", "Signature", "Interface", "Decoder", "Multiplexer"]
__all__ = ["Element", "Signature", "Annotation", "Interface", "Decoder", "Multiplexer"]


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

def annotations(self, element, /):
"""Get annotations of a compatible CSR element.
Parameters
----------
element : :class:`Element`
A CSR element compatible with this signature.
Returns
-------
iterator of :class:`meta.Annotation`
Annotations attached to ``element``.
Raises
------
:exc:`TypeError`
If ``element`` is not an :class:`Element` object.
:exc:`ValueError`
If ``element.signature`` is not equal to ``self``.
"""
if not isinstance(element, Element):
raise TypeError(f"Element must be a csr.Element object, not {element!r}")
if element.signature != self:
raise ValueError(f"Element signature is not equal to this signature")
return (*super().annotations(element), Element.Annotation(element.signature))

def __eq__(self, other):
"""Compare signatures.
Expand All @@ -125,6 +151,64 @@ def __eq__(self, other):
def __repr__(self):
return f"csr.Element.Signature({self.members!r})"

class Annotation(meta.Annotation):
schema = {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://amaranth-lang.org/schema/amaranth-soc/0.1/csr/element.json",
"type": "object",
"properties": {
"width": {
"type": "integer",
"minimum": 0,
},
"access": {
"enum": ["r", "w", "rw"],
},
},
"additionalProperties": False,
"required": [
"width",
"access",
],
}

"""Peripheral-side CSR signature annotation.
Parameters
----------
origin : :class:`Element.Signature`
The signature described by this annotation instance.
Raises
------
:exc:`TypeError`
If ``origin`` is not a :class:`Element.Signature`.
"""
def __init__(self, origin):
if not isinstance(origin, Element.Signature):
raise TypeError(f"Origin must be a csr.Element.Signature object, not {origin!r}")
self._origin = origin

@property
def origin(self):
return self._origin

def as_json(self):
"""Translate to JSON.
Returns
-------
:class:`dict`
A JSON representation of :attr:`~Element.Annotation.origin`, describing its width
and access mode.
"""
instance = {
"width": self.origin.width,
"access": self.origin.access.value,
}
self.validate(instance)
return instance

"""Peripheral-side CSR interface.
A low-level interface to a single atomically readable and writable register in a peripheral.
Expand Down Expand Up @@ -244,6 +328,35 @@ def create(self, *, path=None, src_loc_at=0):
return Interface(addr_width=self.addr_width, data_width=self.data_width,
path=path, src_loc_at=1 + src_loc_at)

def annotations(self, interface, /):
"""Get annotations of a compatible CSR bus interface.
Parameters
----------
interface : :class:`Interface`
A CSR bus interface compatible with this signature.
Returns
-------
iterator of :class:`meta.Annotation`
Annotations attached to ``interface``.
Raises
------
:exc:`TypeError`
If ``interface`` is not an :class:`Interface` object.
:exc:`ValueError`
If ``interface.signature`` is not equal to ``self``.
"""
if not isinstance(interface, Interface):
raise TypeError(f"Interface must be a csr.Interface object, not {interface!r}")
if interface.signature != self:
raise ValueError(f"Interface signature is not equal to this signature")
annotations = [*super().annotations(interface), Annotation(interface.signature)]
if interface._memory_map is not None:
annotations.append(interface._memory_map.annotation)
return annotations

def __eq__(self, other):
"""Compare signatures.
Expand All @@ -257,6 +370,66 @@ def __repr__(self):
return f"csr.Signature({self.members!r})"


class Annotation(meta.Annotation):
schema = {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://amaranth-lang.org/schema/amaranth-soc/0.1/csr/bus.json",
"type": "object",
"properties": {
"addr_width": {
"type": "integer",
"minimum": 0,
},
"data_width": {
"type": "integer",
"minimum": 0,
},
},
"additionalProperties": False,
"required": [
"addr_width",
"data_width",
],
}

"""CPU-side CSR signature annotation.
Parameters
----------
origin : :class:`Signature`
The signature described by this annotation instance.
Raises
------
:exc:`TypeError`
If ``origin`` is not a :class:`Signature`.
"""
def __init__(self, origin):
if not isinstance(origin, Signature):
raise TypeError(f"Origin must be a csr.Signature object, not {origin!r}")
self._origin = origin

@property
def origin(self):
return self._origin

def as_json(self):
"""Translate to JSON.
Returns
-------
:class:`dict`
A JSON representation of :attr:`~Annotation.origin`, describing its address width
and data width.
"""
instance = {
"addr_width": self.origin.addr_width,
"data_width": self.origin.data_width,
}
self.validate(instance)
return instance


class Interface(wiring.PureInterface):
"""CPU-side CSR interface.
Expand Down
Loading

0 comments on commit 4cd6f94

Please sign in to comment.