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