1- from functools import reduce
1+ import enum
22from nmigen import *
3- from nmigen import tracer
43
54
65__all__ = ["Element" , "Interface" , "Decoder" ]
76
87
98class Element (Record ):
9+ class Access (enum .Enum ):
10+ """Register access mode.
11+
12+ Coarse access mode for the entire register. Individual fields can have more restrictive
13+ access mode, e.g. R/O fields can be a part of an R/W register.
14+ """
15+ R = "r"
16+ W = "w"
17+ RW = "rw"
18+
19+ def readable (self ):
20+ return self == self .R or self == self .RW
21+
22+ def writable (self ):
23+ return self == self .W or self == self .RW
24+
1025 """Peripheral-side CSR interface.
1126
1227 A low-level interface to a single atomically readable and writable register in a peripheral.
@@ -17,6 +32,8 @@ class Element(Record):
1732 ----------
1833 width : int
1934 Width of the register.
35+ access : :class:`Access`
36+ Register access mode.
2037 name : str
2138 Name of the underlying record.
2239
@@ -37,19 +54,19 @@ def __init__(self, width, access, *, name=None, src_loc_at=0):
3754 if not isinstance (width , int ) or width < 0 :
3855 raise ValueError ("Width must be a non-negative integer, not {!r}"
3956 .format (width ))
40- if access not in ("r" , "w" , "rw" ):
57+ if not isinstance ( access , Element . Access ) and access not in ("r" , "w" , "rw" ):
4158 raise ValueError ("Access mode must be one of \" r\" , \" w\" , or \" rw\" , not {!r}"
4259 .format (access ))
4360 self .width = width
44- self .access = access
61+ self .access = Element . Access ( access )
4562
4663 layout = []
47- if "r" in self .access :
64+ if self .access . readable () :
4865 layout += [
4966 ("r_data" , width ),
5067 ("r_stb" , 1 ),
5168 ]
52- if "w" in self .access :
69+ if self .access . writable () :
5370 layout += [
5471 ("w_data" , width ),
5572 ("w_stb" , 1 ),
@@ -240,7 +257,7 @@ def elaborate(self, platform):
240257
241258 for elem_addr , (elem , elem_size ) in self ._elements .items ():
242259 shadow = Signal (elem .width , name = "{}__shadow" .format (elem .name ))
243- if "w" in elem .access :
260+ if elem .access . writable () :
244261 m .d .comb += elem .w_data .eq (shadow )
245262
246263 # Enumerate every address used by the register explicitly, rather than using
@@ -252,7 +269,7 @@ def elaborate(self, platform):
252269 chunk_slice = slice (chunk_offset * self .bus .data_width ,
253270 (chunk_offset + 1 ) * self .bus .data_width )
254271 with m .Case (elem_addr + chunk_offset ):
255- if "r" in elem .access :
272+ if elem .access . readable () :
256273 chunk_r_stb = Signal (self .bus .data_width ,
257274 name = "{}__r_stb_{}" .format (elem .name , chunk_offset ))
258275 r_data_fanin |= Mux (chunk_r_stb , shadow [chunk_slice ], 0 )
@@ -263,7 +280,7 @@ def elaborate(self, platform):
263280 # Delay by 1 cycle, allowing reads to be pipelined.
264281 m .d .sync += chunk_r_stb .eq (self .bus .r_stb )
265282
266- if "w" in elem .access :
283+ if elem .access . writable () :
267284 if chunk_offset == elem_size - 1 :
268285 # Delay by 1 cycle, avoiding combinatorial paths through
269286 # the CSR bus and into CSR registers.
0 commit comments