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