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