start putting LDSTSplitter together
[soc.git] / src / soc / minerva / csr.py
1 from enum import Enum
2 from collections import OrderedDict
3
4 from nmigen import (Const, Elaboratable, Module, Mux,
5 Record, Signal,)
6 from nmigen.utils import bits_for
7
8
9 __all__ = ["CSRAccess", "CSR", "AutoCSR", "CSRFile"]
10
11
12 CSRAccess = Enum("CSRAccess", ("WIRI", "WPRI", "WLRL", "WARL"))
13
14
15 class CSR():
16 def __init__(self, addr, description, name):
17 fields = []
18 mask = 0
19 offset = 0
20 for name, shape, access in description:
21 if isinstance(shape, int):
22 shape = shape, False
23 nbits, signed = shape
24 fields.append((name, shape))
25 if access in {CSRAccess.WLRL, CSRAccess.WARL}:
26 mask |= ((1 << nbits) - 1) << offset
27 offset += nbits
28
29 self.addr = addr
30 self.rmask = self.wmask = Const(mask)
31 self.r = Record(fields)
32 self.w = Record(fields)
33 self.re = Signal()
34 self.we = Signal()
35
36
37 class AutoCSR():
38 def iter_csrs(self):
39 for v in vars(self).values():
40 if isinstance(v, CSR):
41 yield v
42 elif hasattr(v, "iter_csrs"):
43 yield from v.iter_csrs()
44
45
46 class CSRFile(Elaboratable):
47 def __init__(self, width=32, depth=2**12):
48 self.width = width
49 self.depth = depth
50 self._csr_map = OrderedDict()
51 self._read_ports = []
52 self._write_ports = []
53
54 def add_csrs(self, csrs):
55 for csr in 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"
60 .format(csr.addr))
61 self._csr_map[csr.addr] = csr
62
63 def read_port(self):
64 port = Record([("addr", bits_for(self.depth)), ("en", 1), ("data", self.width)])
65 self._read_ports.append(port)
66 return port
67
68 def write_port(self):
69 port = Record([("addr", bits_for(self.depth)), ("en", 1), ("data", self.width)])
70 self._write_ports.append(port)
71 return port
72
73 def elaborate(self, platform):
74 m = Module()
75
76 for rp in self._read_ports:
77 with m.Switch(rp.addr):
78 for addr, csr in self._csr_map.items():
79 with m.Case(addr):
80 m.d.comb += [
81 csr.re.eq(rp.en),
82 rp.data.eq(csr.r & csr.rmask)
83 ]
84
85 for wp in self._write_ports:
86 with m.Switch(wp.addr):
87 for addr, csr in self._csr_map.items():
88 with m.Case(addr):
89 m.d.comb += [
90 csr.we.eq(wp.en),
91 csr.w.eq(wp.data & csr.wmask)
92 ]
93
94 return m