CSR registers
The amaranth_soc.csr.reg module provides a way to define and create CSR registers and register fields.
Introduction
Control and Status registers are commonly used as an interface between SoC peripherals and the firmware that operates them.
This module provides the following functionality:
Register field description and implementation via the
FieldandFieldActionclasses. Theamaranth_soc.csr.actionmodule provides a built-inFieldActionsubclasses for common use cases. If needed, users can implement their own subclasses.Composable layouts of register fields via
FieldActionMapandFieldActionArray. These classes are not meant to be instantiated directly, but are useful when introspecting the layout of a register.Register definitions via the
Registerclass. The fields of a register can be provided as variable annotations or as instance parameters.A
Builderclass to organize registers of a peripheral into a hierarchy of clusters and arrays, to be converted into aMemoryMap.A bridge between a CSR bus interface and the registers of a peripheral, via the
Bridgeclass.
Examples
Defining a register declaratively
If its layout and access mode are known in advance, a register can be concisely defined using variable annotations:
class Status(csr.Register, access="rw"):
rdy: csr.Field(csr.action.R, 1)
err: csr.Field(csr.action.RW1C, 1)
_unimp: csr.Field(csr.action.ResR0W0, 6)
Note
By convention, names of reserved fields (such as _unimp in the above example) should begin with an underscore.
Defining a register with instance parameters
If the layout or access mode of a register aren’t known until instantiation, a Register subclass can override them in __init__:
class Data(csr.Register):
def __init__(self, width=8, access="w"):
super().__init__(fields={"data": csr.Field(csr.action.W, width)},
access=access)
Defining a single-field register
In the previous example, the Data register has a single field named "Data.data", which is redundant.
If no other fields are expected to be added in future revisions of the peripheral (or forward compatibility is not a concern), the field name can be omitted like so:
class Data(csr.Register, access="w"):
def __init__(self):
super().__init__(csr.Field(csr.action.W, 8))
Defining a register with nested fields
Hierarchical layouts of register fields can be expressed using lists and dicts:
class SetClr(csr.Register, access="r"):
pin: [{"set": csr.Field(csr.action.W, 1),
"clr": csr.Field(csr.action.W, 1)} for _ in range(8)]
Connecting registers to a CSR bus
In this example, the registers of FooPeripheral are added to a Builder to produce a memory map, and then bridged to a bus interface:
class FooPeripheral(wiring.Component):
class Ctrl(csr.Register, access="rw"):
enable: csr.Field(csr.action.RW, 1)
_unimp: csr.Field(csr.action.ResR0W0, 7)
class Data(csr.Register, access="r"):
def __init__(self, width):
super().__init__(csr.Field(csr.action.R, width))
def __init__(self):
regs = csr.Builder(addr_width=4, data_width=8)
reg_ctrl = regs.add("Ctrl", Ctrl())
reg_data = regs.add("Data", Data(width=32), offset=4)
self._bridge = csr.Bridge(regs.as_memory_map())
super().__init__({"csr_bus": In(csr.Signature(addr_width=4, data_width=8))})
self.csr_bus.memory_map = self._bridge.bus.memory_map
def elaborate(self, platform):
return Module() # ...
Defining a custom field action
If amaranth_soc.csr.action built-ins do not cover a desired use case, a custom FieldAction may provide an alternative.
This example shows a “read/write-0-to-set” field action:
class RW0S(csr.FieldAction):
def __init__(self, shape, init=0):
super().__init__(shape, access="rw", members={
"data": Out(shape),
"clear": In(shape),
})
self._storage = Signal(shape, init=init)
self._init = init
@property
def init(self):
return self._init
def elaborate(self, platform):
m = Module()
for i, storage_bit in enumerate(self._storage):
with m.If(self.clear[i]):
m.d.sync += storage_bit.eq(0)
with m.If(self.port.w_stb & ~self.port.w_data[i]):
m.d.sync += storage_bit.eq(1)
m.d.comb += [
self.port.r_data.eq(self._storage),
self.data.eq(self._storage),
]
return m
RW0S can then be passed to Field:
class Foo(csr.Register, access="rw"):
mask: csr.Field(RW0S, 8)
data: csr.Field(csr.action.RW, 8)
Fields
- class FieldPort.Access
Field access mode.
- R = 'r'
- W = 'w'
- RW = 'rw'
- NC = 'nc'
- readable()
- writable()
- class FieldPort.Signature
CSR register field port signature.
- Parameters:
shape (shape-like object) – Shape of the field.
access (
FieldPort.Access) – Field access mode.attributes (Interface)
--------------------
r_data (Signal(shape)) – Read data. Must always be valid, and is sampled when
r_stbis asserted.r_stb (Signal()) – Read strobe. Fields with read side effects should perform them when this strobe is asserted.
w_data (Signal(shape)) – Write data. Valid only when
w_stbis asserted.w_stb (Signal()) – Write strobe. Fields should update their value or perform the write side effect when this strobe is asserted.
- create(*, path=None, src_loc_at=0)
Create a compatible interface.
See
wiring.Signature.create()for details.- Return type:
A
FieldPortobject using this signature.
- __eq__(other)
Compare signatures.
Two signatures are equal if they have the same shape and field access mode.
- class amaranth_soc.csr.reg.FieldPort
- class amaranth_soc.csr.reg.Field
Description of a CSR register field.
- Parameters:
action_cls (
FieldActionsubclass) – The type of field action to be instantiated byField.create().*args (
tuple) – Positional arguments passed toaction_cls.__init__.**kwargs (
dict) – Keyword arguments passed toaction_cls.__init__.
- Raises:
TypeError – If
action_clsis not a subclass ofFieldAction.
- create()
Instantiate a field action.
- Returns:
The object returned by
action_cls(*args, **kwargs).- Return type:
Field actions
- class amaranth_soc.csr.reg.FieldAction
CSR register field action.
A
Componentmediating access between a CSR bus and a range of bits within aRegister.- Parameters:
shape (shape-like object) – Shape of the field. See
FieldPort.Signature.access (
FieldPort.Access) – Field access mode. SeeFieldPort.Signature.members (iterable of (
str,wiring.Member) key/value pairs) – Signature members. Optional, defaults to(). AFieldPort.Signaturemember named ‘port’ and oriented as input is always present in addition to these members.attributes (Interface)
--------------------
port (
FieldPort) – Field port.
- Raises:
ValueError – If the key ‘port’ is used in
members.
- class amaranth_soc.csr.reg.FieldActionMap
A mapping of field actions.
- Parameters:
fields (
dictofstrto (Fieldordictorlist)) –- Register fields. Fields are instantiated according to their type:
a
Fieldis instantiated as aFieldAction(seeField.create());a
dictis instantiated as aFieldActionMap;a
listis instantiated as aFieldArrayMap.
- Raises:
- __getitem__(key)
Access a field by name or index.
- Returns:
The field instance associated with
key.- Return type:
- Raises:
KeyError – If there is no field instance associated with
key.
- __getattr__(name)
Access a field by name.
- Returns:
The field instance associated with
name.- Return type:
- Raises:
AttributeError – If the field map does not have a field instance associated with
name.AttributeError – If
nameis reserved (i.e. starts with an underscore).
- flatten()
Recursively iterate over the field map.
- Yields:
iter(
str) – Path of the field. It is prefixed by the name of every nestedFieldActionMaporFieldActionArray.FieldAction– Field instance.
- class amaranth_soc.csr.reg.FieldActionArray
An array of CSR register fields.
- Parameters:
fields (
listof (Fieldordictorlist)) –- Register fields. Fields are instantiated according to their type:
a
Fieldis instantiated as aFieldAction(seeField.create());a
dictis instantiated as aFieldActionMap;a
listis instantiated as aFieldArrayMap.
- Raises:
- __getitem__(key)
Access a field by index.
- Returns:
The field instance associated with
key.- Return type:
- flatten()
Iterate recursively over the field array.
- Yields:
iter(
str) – Path of the field. It is prefixed by the name of every nestedFieldActionMaporFieldActionArray.FieldAction– Field instance.
Registers
- class amaranth_soc.csr.reg.Register
A CSR register.
- Parameters:
fields (
dictorlistorField) – Collection of register fields. IfNone(default), a dict is populated from Python variable annotations.fieldsis used to create aFieldActionMap,FieldActionArray, orFieldAction, depending on its type (dict, list, or Field).access (
Element.Access) – Element access mode.
Interface attributes
- element
Element Interface between this register and a CSR bus primitive.
- Attributes:
field (
FieldActionMaporFieldActionArrayorFieldAction) – Collection of field instances.f (
FieldActionMaporFieldActionArrayorFieldAction) – Shorthand forRegister.field.
- raises TypeError:
- raises ValueError:
If
fieldsis notNoneand at least one variable annotation is aField.- raises ValueError:
If
element.accessis not readable and at least one field is readable.- raises ValueError:
If
element.accessis not writable and at least one field is writable.
- field
- f
- __iter__()
Recursively iterate over the field collection.
- Yields:
iter(
str) – Path of the field. It is prefixed by the name of every nestedFieldActionMaporFieldActionArray.FieldAction– Field instance.
- class amaranth_soc.csr.reg.Builder
CSR builder.
A CSR builder can organize a group of registers within an address range and convert it to a
MemoryMapfor consumption by other SoC primitives.- Parameters:
- Raises:
TypeError – If
addr_widthis not a positive integer.TypeError – If
data_widthis not a positive integer.TypeError – If
granularityis not a positive integer.ValueError – If
granularityis not a divisor ofdata_width
- freeze()
Freeze the builder.
Once the builder is frozen, CSR registers cannot be added anymore.
- add(name, reg, *, offset=None)
Add a CSR register.
- Parameters:
- Returns:
reg, which is added to the builder. Its name isname, prefixed by the names and indices of any parentCluster()andIndex().- Return type:
- Raises:
ValueError – If the builder is frozen.
TypeError – If
nameis not a string, or is empty.ValueError – If
regis already added to the builder.TypeError – If
offsetis not an integer, or is negative.ValueError – If
offsetis not a multiple ofself.data_width // self.granularity.
- Cluster(name)
Define a cluster.
- Index(index)
Define an array index.
- as_memory_map()
- class amaranth_soc.csr.reg.Bridge
CSR bridge.
- Parameters:
memory_map (
MemoryMap) – Memory map of CSR registers.attributes (Interface)
--------------------
bus (
Interface) – CSR bus providing access to the contents ofmemory_map.
- Raises:
TypeError – If
memory_mapis not aMemoryMapobject.ValueError – If
memory_maphas windows.TypeError – If
memory_maphas resources that are notRegisterobjects.