2 from collections
import OrderedDict
4 from nmigen
import (Const
, Elaboratable
, Module
, Mux
,
6 from nmigen
.utils
import bits_for
9 __all__
= ["CSRAccess", "CSR", "AutoCSR", "CSRFile"]
12 CSRAccess
= Enum("CSRAccess", ("WIRI", "WPRI", "WLRL", "WARL"))
16 def __init__(self
, addr
, description
, name
):
20 for name
, shape
, access
in description
:
21 if isinstance(shape
, int):
24 fields
.append((name
, shape
))
25 if access
in {CSRAccess
.WLRL
, CSRAccess
.WARL
}:
26 mask |
= ((1 << nbits
) - 1) << offset
30 self
.rmask
= self
.wmask
= Const(mask
)
31 self
.r
= Record(fields
)
32 self
.w
= Record(fields
)
39 for v
in vars(self
).values():
40 if isinstance(v
, CSR
):
42 elif hasattr(v
, "iter_csrs"):
43 yield from v
.iter_csrs()
46 class CSRFile(Elaboratable
):
47 def __init__(self
, width
=32, depth
=2**12):
50 self
._csr
_map
= OrderedDict()
52 self
._write
_ports
= []
54 def add_csrs(self
, csrs
):
56 if not isinstance(csr
, CSR
):
57 raise TypeError("Object {!r} is not a CSR".format(csr
))
58 if csr
.addr
in self
._csr
_map
:
59 raise ValueError("CSR address 0x{:x} has already been allocated"
61 self
._csr
_map
[csr
.addr
] = csr
64 port
= Record([("addr", bits_for(self
.depth
)), ("en", 1), ("data", self
.width
)])
65 self
._read
_ports
.append(port
)
69 port
= Record([("addr", bits_for(self
.depth
)), ("en", 1), ("data", self
.width
)])
70 self
._write
_ports
.append(port
)
73 def elaborate(self
, platform
):
76 for rp
in self
._read
_ports
:
77 with m
.Switch(rp
.addr
):
78 for addr
, csr
in self
._csr
_map
.items():
82 rp
.data
.eq(csr
.r
& csr
.rmask
)
85 for wp
in self
._write
_ports
:
86 with m
.Switch(wp
.addr
):
87 for addr
, csr
in self
._csr
_map
.items():
91 csr
.w
.eq(wp
.data
& csr
.wmask
)