11from collections .abc import Mapping , Sequence
2- import enum
32from amaranth import *
3+ from amaranth .lib import enum , wiring
4+ from amaranth .lib .wiring import In , Out
45
56from ..memory import MemoryMap
67from .bus import Element , Multiplexer
910__all__ = ["FieldPort" , "Field" , "FieldMap" , "FieldArray" , "Register" , "RegisterMap" , "Bridge" ]
1011
1112
12- class FieldPort :
13+ class FieldPort ( wiring . Interface ) :
1314 class Access (enum .Enum ):
1415 """Field access mode."""
1516 R = "r"
@@ -22,64 +23,135 @@ def readable(self):
2223 def writable (self ):
2324 return self == self .W or self == self .RW
2425
26+ class Signature (wiring .Signature ):
27+ """CSR register field port signature.
28+
29+ Parameters
30+ ----------
31+ shape : :ref:`shape-castable <lang-shapecasting>`
32+ Shape of the field.
33+ access : :class:`FieldPort.Access`
34+ Field access mode.
35+
36+ Interface attributes
37+ --------------------
38+ r_data : Signal(shape)
39+ Read data. Must always be valid, and is sampled when ``r_stb`` is asserted.
40+ r_stb : Signal()
41+ Read strobe. Fields with read side effects should perform them when this strobe is
42+ asserted.
43+ w_data : Signal(shape)
44+ Write data. Valid only when ``w_stb`` is asserted.
45+ w_stb : Signal()
46+ Write strobe. Fields should update their value or perform the write side effect when
47+ this strobe is asserted.
48+
49+ Raises
50+ ------
51+ See :meth:`FieldPort.Signature.check_parameters`.
52+ """
53+ def __init__ (self , shape , access ):
54+ self .check_parameters (shape , access )
55+
56+ self ._shape = Shape .cast (shape )
57+ self ._access = FieldPort .Access (access )
58+
59+ members = {
60+ "r_data" : Out (self .shape ),
61+ "r_stb" : In (1 ),
62+ "w_data" : In (self .shape ),
63+ "w_stb" : In (1 ),
64+ }
65+ super ().__init__ (members )
66+
67+ @property
68+ def shape (self ):
69+ return self ._shape
70+
71+ @property
72+ def access (self ):
73+ return self ._access
74+
75+ @classmethod
76+ def check_parameters (cls , shape , access ):
77+ """Validate signature parameters.
78+
79+ Raises
80+ ------
81+ :exc:`TypeError`
82+ If ``shape`` is not a shape-castable object.
83+ :exc:`ValueError`
84+ If ``access`` is not a member of :class:`FieldPort.Access`.
85+ """
86+ try :
87+ Shape .cast (shape )
88+ except TypeError as e :
89+ raise TypeError (f"Field shape must be a shape-castable object, not { shape !r} " ) from e
90+ # TODO(py3.9): Remove this. Python 3.8 and below use cls.__name__ in the error message
91+ # instead of cls.__qualname__.
92+ # FieldPort.Access(access)
93+ try :
94+ FieldPort .Access (access )
95+ except ValueError as e :
96+ raise ValueError (f"{ access !r} is not a valid FieldPort.Access" ) from e
97+
98+ def create (self , * , path = ()):
99+ """Create a compatible interface.
100+
101+ See :meth:`wiring.Signature.create` for details.
102+
103+ Returns
104+ -------
105+ A :class:`FieldPort` object using this signature.
106+ """
107+ return FieldPort (self , path = path )
108+
109+ def __eq__ (self , other ):
110+ """Compare signatures.
111+
112+ Two signatures are equal if they have the same shape and field access mode.
113+ """
114+ return (isinstance (other , FieldPort .Signature ) and
115+ Shape .cast (self .shape ) == Shape .cast (other .shape ) and
116+ self .access == other .access )
117+
118+ def __repr__ (self ):
119+ return f"csr.FieldPort.Signature({ self .members !r} )"
120+
25121 """CSR register field port.
26122
27123 An interface between a CSR register and one of its fields.
28124
29125 Parameters
30126 ----------
31- shape : :ref:`shape-castable <lang-shapecasting>`
32- Shape of the field.
33- access : :class:`FieldPort.Access`
34- Field access mode.
35-
36- Attributes
37- ----------
38- r_data : Signal(shape)
39- Read data. Must always be valid, and is sampled when ``r_stb`` is asserted.
40- r_stb : Signal()
41- Read strobe. Fields with read side effects should perform them when this strobe is
42- asserted.
43- w_data : Signal(shape)
44- Write data. Valid only when ``w_stb`` is asserted.
45- w_stb : Signal()
46- Write strobe. Fields should update their value or perform the write side effect when
47- this strobe is asserted.
127+ signature : :class:`FieldPort.Signature`
128+ Field port signature.
129+ path : iter(:class:`str`)
130+ Path to the field port. Optional. See :class:`wiring.Interface`.
48131
49132 Raises
50133 ------
51134 :exc:`TypeError`
52135 If ``shape`` is not a shape-castable object.
53- :exc:`ValueError `
136+ :exc:`TypeError `
54137 If ``access`` is not a member of :class:`FieldPort.Access`.
55138 """
56- def __init__ (self , shape , access ):
57- try :
58- shape = Shape .cast (shape )
59- except TypeError as e :
60- raise TypeError ("Field shape must be a shape-castable object, not {!r}"
61- .format (shape )) from e
62- if not isinstance (access , FieldPort .Access ) and access not in ("r" , "w" , "rw" ):
63- raise ValueError ("Access mode must be one of \" r\" , \" w\" , or \" rw\" , not {!r}"
64- .format (access ))
65- self ._shape = shape
66- self ._access = FieldPort .Access (access )
67-
68- self .r_data = Signal (shape )
69- self .r_stb = Signal ()
70- self .w_data = Signal (shape )
71- self .w_stb = Signal ()
139+ def __init__ (self , signature , * , path = ()):
140+ if not isinstance (signature , FieldPort .Signature ):
141+ raise TypeError (f"This interface requires a csr.FieldPort.Signature, not "
142+ f"{ signature !r} " )
143+ super ().__init__ (signature , path = path )
72144
73145 @property
74146 def shape (self ):
75- return self ._shape
147+ return self .signature . shape
76148
77149 @property
78150 def access (self ):
79- return self ._access
151+ return self .signature . access
80152
81153 def __repr__ (self ):
82- return " FieldPort({}, {})" . format ( self .shape , self . access )
154+ return f"csr. FieldPort({ self .signature !r } )"
83155
84156
85157class Field (Elaboratable ):
@@ -109,7 +181,7 @@ class Field(Elaboratable):
109181 attributes = "" )
110182
111183 def __init__ (self , shape , access ):
112- self .port = FieldPort (shape , access )
184+ self .port = FieldPort . Signature (shape , access ). create ( path = ( "port" ,) )
113185
114186 @property
115187 def shape (self ):
@@ -296,7 +368,7 @@ class Register(Elaboratable):
296368
297369 Raises
298370 ------
299- :exc:`ValueError `
371+ :exc:`TypeError `
300372 If ``access`` is not a member of :class:`Element.Access`.
301373 :exc:`TypeError`
302374 If ``fields`` is not ``None`` or a :class:`FieldMap` or a :class:`FieldArray`.
@@ -305,39 +377,37 @@ class Register(Elaboratable):
305377 :exc:`ValueError`
306378 If ``access`` is not writable and at least one field is writable.
307379 """
308- def __init__ (self , access , fields = None ):
380+ def __init__ (self , access = "rw" , fields = None ):
309381 if not isinstance (access , Element .Access ) and access not in ("r" , "w" , "rw" ):
310- raise ValueError ("Access mode must be one of \" r\" , \" w\" , or \" rw\" , not {!r}"
311- .format (access ))
382+ raise TypeError (f"Access mode must be one of \" r\" , \" w\" , or \" rw\" , not { access !r} " )
312383 access = Element .Access (access )
313384
314385 if hasattr (self , "__annotations__" ):
315- annotation_fields = {}
386+ annot_fields = {}
316387 for key , value in self .__annotations__ .items ():
317388 if isinstance (value , (Field , FieldMap , FieldArray )):
318- annotation_fields [key ] = value
389+ annot_fields [key ] = value
319390
320391 if fields is None :
321- fields = FieldMap (annotation_fields )
322- elif annotation_fields :
323- raise ValueError ("Field collection {} cannot be provided in addition to field annotations: {} "
324- . format ( fields , ", " .join (annotation_fields . keys ())) )
392+ fields = FieldMap (annot_fields )
393+ elif annot_fields :
394+ raise ValueError (f "Field collection { fields } cannot be provided in addition to "
395+ f"field annotations: { ', ' .join (annot_fields ) } " )
325396
326397 if not isinstance (fields , (FieldMap , FieldArray )):
327- raise TypeError ("Field collection must be a FieldMap or a FieldArray, not {!r}"
328- .format (fields ))
398+ raise TypeError (f"Field collection must be a FieldMap or a FieldArray, not { fields !r} " )
329399
330400 width = 0
331401 for field_name , field in fields .flatten ():
332402 width += Shape .cast (field .shape ).width
333403 if field .access .readable () and not access .readable ():
334- raise ValueError ("Field {} is readable, but register access mode is '{}' "
335- . format ( "__" . join ( field_name ), access ) )
404+ raise ValueError (f "Field { '__' . join ( field_name ) } is readable, but register access "
405+ f"mode is { access !r } " )
336406 if field .access .writable () and not access .writable ():
337- raise ValueError ("Field {} is writable, but register access mode is '{}' "
338- . format ( "__" . join ( field_name ), access ) )
407+ raise ValueError (f "Field { '__' . join ( field_name ) } is writable, but register access "
408+ f"mode is { access !r } " )
339409
340- self .element = Element (width , access )
410+ self .element = Element . Signature (width , access ). create ( path = ( "element" ,) )
341411 self ._fields = fields
342412
343413 @property
0 commit comments