Skip to content

Commit aa79198

Browse files
committed
csr.reg: move access= parameter to Register.__init_subclass__().
This allows csr.Register subclasses that use variable annotations to define their access mode without overriding __init__(). In addition, the default value of access= (which was "rw") is removed. The access mode of a register has an influence on the rest of the SoC and should therefore be explicitly set. As a consequence of access= being a required __init_subclass__() kwarg, the csr.Register class can no longer be directly instantiated and must be subclassed first.
1 parent e92c7d9 commit aa79198

File tree

2 files changed

+178
-125
lines changed

2 files changed

+178
-125
lines changed

amaranth_soc/csr/reg.py

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -405,12 +405,10 @@ def flatten(self):
405405

406406

407407
class Register(wiring.Component):
408-
"""CSR register.
408+
"""Base class for CSR registers.
409409
410410
Parameters
411411
----------
412-
access : :class:`Element.Access`
413-
Register access mode.
414412
fields : :class:`dict` or :class:`list`
415413
Collection of register fields. If ``None`` (default), a :class:`dict` is populated from
416414
Python :term:`variable annotations <python:variable annotations>`. If ``fields`` is a
@@ -424,31 +422,39 @@ class Register(wiring.Component):
424422
425423
Attributes
426424
----------
427-
access : :class:`Element.Access`
428-
Register access mode.
429425
fields : :class:`FieldMap` or :class:`FieldArray`
430426
Collection of register fields.
431427
f : :class:`FieldMap` or :class:`FieldArray`
432428
Shorthand for :attr:`Register.fields`.
433429
434430
Raises
435431
------
436-
:exc:`TypeError`
437-
If ``access`` is not a member of :class:`Element.Access`.
438432
:exc:`TypeError`
439433
If ``fields`` is not ``None`` or a :class:`dict` or a :class:`list`.
440434
:exc:`ValueError`
441435
If ``fields`` is not ``None`` and at least one variable annotation is a :class:`Field`.
442436
:exc:`ValueError`
443-
If ``access`` is not readable and at least one field is readable.
437+
If ``element.access`` is not readable and at least one field is readable.
444438
:exc:`ValueError`
445-
If ``access`` is not writable and at least one field is writable.
439+
If ``element.access`` is not writable and at least one field is writable.
446440
"""
447-
def __init__(self, access="rw", fields=None):
448-
if not isinstance(access, Element.Access) and access not in ("r", "w", "rw"):
449-
raise TypeError(f"Access mode must be one of \"r\", \"w\", or \"rw\", not {access!r}")
450-
self._access = Element.Access(access)
451441

442+
def __new__(cls, *args, **kwargs):
443+
if cls is Register:
444+
raise TypeError("csr.Register is a base class and cannot be directly instantiated")
445+
return super().__new__(cls, *args, **kwargs)
446+
447+
def __init_subclass__(cls, *, access, **kwargs):
448+
# TODO(py3.9): Remove this. Python 3.8 and below use cls.__name__ in the error message
449+
# instead of cls.__qualname__.
450+
# cls.__access = Element.Access(access)
451+
try:
452+
cls.__access = Element.Access(access)
453+
except ValueError as e:
454+
raise ValueError(f"{access!r} is not a valid Element.Access") from e
455+
super().__init_subclass__(**kwargs)
456+
457+
def __init__(self, fields=None):
452458
if hasattr(self, "__annotations__"):
453459
def filter_dict(d):
454460
fields = {}
@@ -494,18 +500,14 @@ def filter_list(l):
494500
width = 0
495501
for field_path, field in self._fields.flatten():
496502
width += Shape.cast(field.port.shape).width
497-
if field.port.access.readable() and not self._access.readable():
503+
if field.port.access.readable() and not self.__access.readable():
498504
raise ValueError(f"Field {'__'.join(field_path)} is readable, but register access "
499-
f"mode is {self._access!r}")
500-
if field.port.access.writable() and not self._access.writable():
505+
f"mode is {self.__access!r}")
506+
if field.port.access.writable() and not self.__access.writable():
501507
raise ValueError(f"Field {'__'.join(field_path)} is writable, but register access "
502-
f"mode is {self._access!r}")
508+
f"mode is {self.__access!r}")
503509

504-
super().__init__({"element": Out(Element.Signature(width, self._access))})
505-
506-
@property
507-
def access(self):
508-
return self._access
510+
super().__init__({"element": Out(Element.Signature(width, self.__access))})
509511

510512
@property
511513
def fields(self):

0 commit comments

Comments
 (0)