Skip to content

Commit

Permalink
csr.reg: defer Field creation until Register.__init__().
Browse files Browse the repository at this point in the history
Before this commit, a Register whose fields were variable annotations
couldn't be instantiated more than once, as the latter belonged to the
global scope.

The Field class is now a factory for user-defined field components,
instead of a base class. Every `FieldMap` or `FieldArray` sharing a
Field will use a different instance of its component, obtained from
Field.create().

Also:
* update to follow RFCs 37 and 38
* docstring and diagnostics improvements.
  • Loading branch information
jfng committed Dec 15, 2023
1 parent 60b2fd8 commit f5bfa22
Show file tree
Hide file tree
Showing 3 changed files with 633 additions and 398 deletions.
150 changes: 90 additions & 60 deletions amaranth_soc/csr/field.py
Original file line number Diff line number Diff line change
@@ -1,73 +1,92 @@
from amaranth import *
from amaranth.lib import wiring
from amaranth.lib.wiring import In, Out

from .reg import Field
from .reg import FieldPort


__all__ = ["R", "W", "RW", "RW1C", "RW1S"]


class R(Field):
__doc__ = Field._doc_template.format(
description="""
A read-only field.
""".strip(),
parameters="",
attributes="""
class R(wiring.Component):
"""A read-only field.
Parameters
----------
shape : :ref:`shape-castable <lang-shapecasting>`
Shape of the field.
Interface attributes
--------------------
port : :class:`FieldPort`
Field port.
r_data : Signal(shape)
Read data. Drives the :attr:`~FieldPort.r_data` signal of ``port``.
""".strip())

"""
def __init__(self, shape):
super().__init__(shape, access="r")
self.r_data = Signal(shape)
super().__init__({
"port": In(FieldPort.Signature(shape, access="r")),
"r_data": In(shape),
})

def elaborate(self, platform):
m = Module()
m.d.comb += self.port.r_data.eq(self.r_data)
return m


class W(Field):
__doc__ = Field._doc_template.format(
description="""
A write-only field.
""".strip(),
parameters="",
attributes="""
class W(wiring.Component):
"""A write-only field.
Parameters
----------
shape : :ref:`shape-castable <lang-shapecasting>`
Shape of the field.
Interface attributes
--------------------
port : :class:`FieldPort`
Field port.
w_data : Signal(shape)
Write data. Driven by the :attr:`~FieldPort.w_data` signal of ``port``.
""".strip())

"""
def __init__(self, shape):
super().__init__(shape, access="w")
self.w_data = Signal(shape)
super().__init__({
"port": In(FieldPort.Signature(shape, access="w")),
"w_data": Out(shape),
})

def elaborate(self, platform):
m = Module()
m.d.comb += self.w_data.eq(self.port.w_data)
return m


class RW(Field):
__doc__ = Field._doc_template.format(
description="""
A read/write field with built-in storage.
class RW(wiring.Component):
"""A read/write field with built-in storage.
Storage is updated with the value of ``port.w_data`` one clock cycle after ``port.w_stb`` is
asserted.
""".strip(),
parameters="""
Parameters
----------
shape : :ref:`shape-castable <lang-shapecasting>`
Shape of the field.
reset : :class:`int`
Storage reset value.
""",
attributes="""
Interface attributes
--------------------
port : :class:`FieldPort`
Field port.
data : Signal(shape)
Storage output.
""".strip())

"""
def __init__(self, shape, *, reset=0):
super().__init__(shape, access="rw")
self.data = Signal(shape)
super().__init__({
"port": In(FieldPort.Signature(shape, access="rw")),
"data": Out(shape),
})
self._storage = Signal(shape, reset=reset)
self._reset = reset

Expand All @@ -89,32 +108,37 @@ def elaborate(self, platform):
return m


class RW1C(Field):
__doc__ = Field._doc_template.format(
description="""
A read/write-one-to-clear field with built-in storage.
class RW1C(wiring.Component):
"""A read/write-one-to-clear field with built-in storage.
Storage bits are:
* cleared by high bits in ``port.w_data``, one clock cycle after ``port.w_stb`` is asserted;
* set by high bits in ``set``, one clock cycle after they are asserted.
If a storage bit is set and cleared on the same clock cycle, setting it has precedence.
""".strip(),
parameters="""
Parameters
----------
shape : :ref:`shape-castable <lang-shapecasting>`
Shape of the field.
reset : :class:`int`
Storage reset value.
""",
attributes="""
Interface attributes
--------------------
port : :class:`FieldPort`
Field port.
data : Signal(shape)
Storage output.
set : Signal(shape)
Mask to set storage bits.
""".strip())

"""
def __init__(self, shape, *, reset=0):
super().__init__(shape, access="rw")
self.data = Signal(shape)
self.set = Signal(shape)
super().__init__({
"port": In(FieldPort.Signature(shape, access="rw")),
"data": Out(shape),
"set": In(shape),
})
self._storage = Signal(shape, reset=reset)
self._reset = reset

Expand All @@ -139,31 +163,37 @@ def elaborate(self, platform):
return m


class RW1S(Field):
__doc__ = Field._doc_template.format(
description="""
A read/write-one-to-set field with built-in storage.
class RW1S(wiring.Component):
"""A read/write-one-to-set field with built-in storage.
Storage bits are:
* set by high bits in ``port.w_data``, one clock cycle after ``port.w_stb`` is asserted;
* cleared by high bits in ``clear``, one clock cycle after they are asserted.
If a storage bit is set and cleared on the same clock cycle, setting it has precedence.
""".strip(),
parameters="""
Parameters
----------
shape : :ref:`shape-castable <lang-shapecasting>`
Shape of the field.
reset : :class:`int`
Storage reset value.
""",
attributes="""
Interface attributes
--------------------
port : :class:`FieldPort`
Field port.
data : Signal(shape)
Storage output.
clear : Signal(shape)
Mask to clear storage bits.
""".strip())
"""
def __init__(self, shape, *, reset=0):
super().__init__(shape, access="rw")
self.data = Signal(shape)
self.clear = Signal(shape)
super().__init__({
"port": In(FieldPort.Signature(shape, access="rw")),
"clear": In(shape),
"data": Out(shape),
})
self._storage = Signal(shape, reset=reset)
self._reset = reset

Expand Down
Loading

0 comments on commit f5bfa22

Please sign in to comment.