csr.bus: rewrite using the MemoryMap abstraction.
[nmigen-soc.git] / nmigen_soc / csr / bus.py
1 import enum
2 from nmigen import *
3
4 from ..memory import MemoryMap
5
6
7 __all__ = ["Element", "Interface", "Decoder"]
8
9
10 class Element(Record):
11 class Access(enum.Enum):
12 """Register access mode.
13
14 Coarse access mode for the entire register. Individual fields can have more restrictive
15 access mode, e.g. R/O fields can be a part of an R/W register.
16 """
17 R = "r"
18 W = "w"
19 RW = "rw"
20
21 def readable(self):
22 return self == self.R or self == self.RW
23
24 def writable(self):
25 return self == self.W or self == self.RW
26
27 """Peripheral-side CSR interface.
28
29 A low-level interface to a single atomically readable and writable register in a peripheral.
30 This interface supports any register width and semantics, provided that both reads and writes
31 always succeed and complete in one cycle.
32
33 Parameters
34 ----------
35 width : int
36 Width of the register.
37 access : :class:`Access`
38 Register access mode.
39 name : str
40 Name of the underlying record.
41
42 Attributes
43 ----------
44 r_data : Signal(width)
45 Read data. Must be always valid, and is sampled when ``r_stb`` is asserted.
46 r_stb : Signal()
47 Read strobe. Registers with read side effects should perform the read side effect when this
48 strobe is asserted.
49 w_data : Signal(width)
50 Write data. Valid only when ``w_stb`` is asserted.
51 w_stb : Signal()
52 Write strobe. Registers should update their value or perform the write side effect when
53 this strobe is asserted.
54 """
55 def __init__(self, width, access, *, name=None, src_loc_at=0):
56 if not isinstance(width, int) or width < 0:
57 raise ValueError("Width must be a non-negative integer, not {!r}"
58 .format(width))
59 if not isinstance(access, Element.Access) and access not in ("r", "w", "rw"):
60 raise ValueError("Access mode must be one of \"r\", \"w\", or \"rw\", not {!r}"
61 .format(access))
62 self.width = width
63 self.access = Element.Access(access)
64
65 layout = []
66 if self.access.readable():
67 layout += [
68 ("r_data", width),
69 ("r_stb", 1),
70 ]
71 if self.access.writable():
72 layout += [
73 ("w_data", width),
74 ("w_stb", 1),
75 ]
76 super().__init__(layout, name=name, src_loc_at=1)
77
78 # FIXME: get rid of this
79 __hash__ = object.__hash__
80
81
82 class Interface(Record):
83 """CPU-side CSR interface.
84
85 A low-level interface to a set of atomically readable and writable peripheral CSR registers.
86
87 Operation
88 ---------
89
90 CSR registers mapped to the CSR bus are split into chunks according to the bus data width.
91 Each chunk is assigned a consecutive address on the bus. This allows accessing CSRs of any
92 size using any datapath width.
93
94 When the first chunk of a register is read, the value of a register is captured, and reads
95 from subsequent chunks of the same register return the captured values. When any chunk except
96 the last chunk of a register is written, the written value is captured; a write to the last
97 chunk writes the captured value to the register. This allows atomically accessing CSRs larger
98 than datapath width.
99
100 Parameters
101 ----------
102 addr_width : int
103 Address width. At most ``(2 ** addr_width) * data_width`` register bits will be available.
104 data_width : int
105 Data width. Registers are accessed in ``data_width`` sized chunks.
106 name : str
107 Name of the underlying record.
108
109 Attributes
110 ----------
111 addr : Signal(addr_width)
112 Address for reads and writes.
113 r_data : Signal(data_width)
114 Read data. Valid on the next cycle after ``r_stb`` is asserted.
115 r_stb : Signal()
116 Read strobe. If ``addr`` points to the first chunk of a register, captures register value
117 and causes read side effects to be performed (if any). If ``addr`` points to any chunk
118 of a register, latches the captured value to ``r_data``. Otherwise, latches zero
119 to ``r_data``.
120 w_data : Signal(data_width)
121 Write data. Must be valid when ``w_stb`` is asserted.
122 w_stb : Signal()
123 Write strobe. If ``addr`` points to the last chunk of a register, writes captured value
124 to the register and causes write side effects to be performed (if any). If ``addr`` points
125 to any chunk of a register, latches ``w_data`` to the captured value. Otherwise, does
126 nothing.
127 """
128
129 def __init__(self, *, addr_width, data_width, name=None):
130 if not isinstance(addr_width, int) or addr_width <= 0:
131 raise ValueError("Address width must be a positive integer, not {!r}"
132 .format(addr_width))
133 if not isinstance(data_width, int) or data_width <= 0:
134 raise ValueError("Data width must be a positive integer, not {!r}"
135 .format(data_width))
136 self.addr_width = addr_width
137 self.data_width = data_width
138
139 super().__init__([
140 ("addr", addr_width),
141 ("r_data", data_width),
142 ("r_stb", 1),
143 ("w_data", data_width),
144 ("w_stb", 1),
145 ], name=name, src_loc_at=1)
146
147
148 class Decoder(Elaboratable):
149 """CSR bus decoder.
150
151 An address-based multiplexer for CSR registers implementing atomic updates.
152
153 Latency
154 -------
155
156 Writes are registered, and are performed 1 cycle after ``w_stb`` is asserted.
157
158 Alignment
159 ---------
160
161 Because the CSR bus conserves logic and routing resources, it is common to e.g. access
162 a CSR bus with an *n*-bit data path from a CPU with a *k*-bit datapath (*k>n*) in cases
163 where CSR access latency is less important than resource usage. In this case, two strategies
164 are possible for connecting the CSR bus to the CPU:
165 * The CPU could access the CSR bus directly (with no intervening logic other than simple
166 translation of control signals). In this case, the register alignment should be set
167 to 1, and each *w*-bit register would occupy *ceil(w/n)* addresses from the CPU
168 perspective, requiring the same amount of memory instructions to access.
169 * The CPU could also access the CSR bus through a width down-converter, which would issue
170 *k/n* CSR accesses for each CPU access. In this case, the register alignment should be
171 set to *k/n*, and each *w*-bit register would occupy *ceil(w/k)* addresses from the CPU
172 perspective, requiring the same amount of memory instructions to access.
173
174 If alignment is greater than 1, it affects which CSR bus write is considered a write to
175 the last register chunk. For example, if a 24-bit register is used with a 8-bit CSR bus and
176 a CPU with a 32-bit datapath, a write to this register requires 4 CSR bus writes to complete
177 and the 4th write is the one that actually writes the value to the register. This allows
178 determining write latency solely from the amount of addresses the register occupies in
179 the CPU address space, and the width of the CSR bus.
180
181 Parameters
182 ----------
183 addr_width : int
184 Address width. See :class:`Interface`.
185 data_width : int
186 Data width. See :class:`Interface`.
187 alignment : int
188 Register alignment. The address assigned to each register will be a multiple of
189 ``2 ** alignment``.
190
191 Attributes
192 ----------
193 bus : :class:`Interface`
194 CSR bus providing access to registers.
195 """
196 def __init__(self, *, addr_width, data_width, alignment=0):
197 self.bus = Interface(addr_width=addr_width, data_width=data_width)
198 self._map = MemoryMap(addr_width=addr_width, data_width=data_width, alignment=alignment)
199
200 def align_to(self, alignment):
201 """Align the implicit address of the next register.
202
203 See :meth:`MemoryMap.align_to` for details.
204 """
205 return self._map.align_to(alignment)
206
207 def add(self, element, *, addr=None, alignment=None):
208 """Add a register.
209
210 See :meth:`MemoryMap.add_resource` for details.
211 """
212 if not isinstance(element, Element):
213 raise TypeError("Element must be an instance of csr.Element, not {!r}"
214 .format(element))
215
216 size = (element.width + self.bus.data_width - 1) // self.bus.data_width
217 return self._map.add_resource(element, size=size, addr=addr, alignment=alignment)
218
219 def elaborate(self, platform):
220 m = Module()
221
222 # Instead of a straightforward multiplexer for reads, use a per-element address comparator,
223 # AND the shadow register chunk with the comparator output, and OR all of those together.
224 # If the toolchain doesn't already synthesize multiplexer trees this way, this trick can
225 # save a significant amount of logic, since e.g. one 4-LUT can pack one 2-MUX, but two
226 # 2-AND or 2-OR gates.
227 r_data_fanin = 0
228
229 for elem, (elem_start, elem_end) in self._map.resources():
230 shadow = Signal(elem.width, name="{}__shadow".format(elem.name))
231 if elem.access.writable():
232 m.d.comb += elem.w_data.eq(shadow)
233
234 # Enumerate every address used by the register explicitly, rather than using
235 # arithmetic comparisons, since some toolchains (e.g. Yosys) are too eager to infer
236 # carry chains for comparisons, even with a constant. (Register sizes don't have
237 # to be powers of 2.)
238 with m.Switch(self.bus.addr):
239 for chunk_offset, chunk_addr in enumerate(range(elem_start, elem_end)):
240 with m.Case(chunk_addr):
241 shadow_slice = shadow[chunk_offset * self.bus.data_width:
242 (chunk_offset + 1) * self.bus.data_width]
243
244 if elem.access.readable():
245 chunk_r_stb = Signal(self.bus.data_width,
246 name="{}__r_stb_{}".format(elem.name, chunk_offset))
247 r_data_fanin |= Mux(chunk_r_stb, shadow_slice, 0)
248 if chunk_addr == elem_start:
249 m.d.comb += elem.r_stb.eq(self.bus.r_stb)
250 with m.If(self.bus.r_stb):
251 m.d.sync += shadow.eq(elem.r_data)
252 # Delay by 1 cycle, allowing reads to be pipelined.
253 m.d.sync += chunk_r_stb.eq(self.bus.r_stb)
254
255 if elem.access.writable():
256 if chunk_addr == elem_end - 1:
257 # Delay by 1 cycle, avoiding combinatorial paths through
258 # the CSR bus and into CSR registers.
259 m.d.sync += elem.w_stb.eq(self.bus.w_stb)
260 with m.If(self.bus.w_stb):
261 m.d.sync += shadow_slice.eq(self.bus.w_data)
262
263 with m.Default():
264 m.d.sync += shadow.eq(0)
265
266 m.d.comb += self.bus.r_data.eq(r_data_fanin)
267
268 return m