2 from nmigen
import Record
, Elaboratable
, Module
, Signal
, Mux
3 from nmigen
.utils
import log2_int
5 from nmigen_soc
.memory
import MemoryMap
8 __all__
= ["Element", "Interface", "Decoder", "Multiplexer"]
11 class Element(Record
):
12 class Access(enum
.Enum
):
13 """Register access mode.
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.
24 return self
== self
.R
or self
== self
.RW
27 return self
== self
.W
or self
== self
.RW
29 """Peripheral-side CSR interface.
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.
39 Width of the register.
40 access : :class:`Access`
43 Name of the underlying record.
47 r_data : Signal(width)
48 Read data. Must be always valid, and is sampled when ``r_stb``
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.
56 Write strobe. Registers should update their value or perform
57 the write side effect when this strobe is asserted.
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}"
64 if not isinstance(access
, Element
.Access
) and access
not in (
66 raise ValueError("Access mode must be one of \"r\", "
67 "\"w\", or \"rw\", not {!r}"
70 self
.access
= Element
.Access(access
)
73 if self
.access
.readable():
78 if self
.access
.writable():
83 super().__init
__(layout
, name
=name
, src_loc_at
=1)
85 # FIXME: get rid of this
86 __hash__
= object.__hash
__
89 class Interface(Record
):
90 """CPU-side CSR interface.
92 A low-level interface to a set of atomically readable and writable
93 peripheral CSR registers.
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
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.
113 Address width. At most ``(2 ** addr_width) * data_width``
114 register bits will be available.
116 Data width. Registers are accessed in ``data_width`` sized chunks.
118 Register and window alignment. See :class:`MemoryMap`.
120 Name of the underlying record.
124 memory_map : MemoryMap
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.)
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.
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.
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}"
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
,
162 ("addr", addr_width
),
163 ("r_data", data_width
),
165 ("w_data", data_width
),
167 ], name
=name
, src_loc_at
=1)
170 class Multiplexer(Elaboratable
):
171 """CSR register multiplexer.
173 An address-based multiplexer for CSR registers implementing atomic updates.
178 Writes are registered, and are performed 1 cycle after ``w_stb``
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
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.
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.
214 Address width. See :class:`Interface`.
216 Data width. See :class:`Interface`.
218 Register alignment. See :class:`Interface`.
222 bus : :class:`Interface`
223 CSR bus providing access to registers.
226 def __init__(self
, *, addr_width
, data_width
, alignment
=0):
227 self
.bus
= Interface(addr_width
=addr_width
,
228 data_width
=data_width
,
231 self
._map
= self
.bus
.memory_map
233 def align_to(self
, alignment
):
234 """Align the implicit address of the next register.
236 See :meth:`MemoryMap.align_to` for details.
238 return self
._map
.align_to(alignment
)
240 def add(self
, element
, *, addr
=None, alignment
=None):
243 See :meth:`MemoryMap.add_resource` for details.
245 if not isinstance(element
, Element
):
246 raise TypeError("Element must be an instance of csr.Element, "
247 "not {!r}" .format(element
))
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
)
253 def elaborate(self
, platform
):
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.
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():
268 elem_end
- elem_start
,
269 name
="{}__shadow_en".format(
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)
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
)
287 with m
.Case(chunk_addr
):
288 if elem
.access
.readable():
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
<<
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
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
)
308 m
.d
.comb
+= self
.bus
.r_data
.eq(r_data_fanin
)
313 class Decoder(Elaboratable
):
316 An address decoder for subordinate CSR buses.
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.
335 Address width. See :class:`Interface`.
337 Data width. See :class:`Interface`.
339 Window alignment. See :class:`Interface`.
343 bus : :class:`Interface`
344 CSR bus providing access to subordinate buses.
347 def __init__(self
, *, addr_width
, data_width
, alignment
=0):
348 self
.bus
= Interface(addr_width
=addr_width
,
349 data_width
=data_width
,
352 self
._map
= self
.bus
.memory_map
355 def align_to(self
, alignment
):
356 """Align the implicit address of the next window.
358 See :meth:`MemoryMap.align_to` for details.
360 return self
._map
.align_to(alignment
)
362 def add(self
, sub_bus
, *, addr
=None):
363 """Add a window to a subordinate bus.
365 See :meth:`MemoryMap.add_resource` for details.
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
)
378 def elaborate(self
, platform
):
381 # See Multiplexer.elaborate above.
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
388 sub_bus
= self
._subs
[sub_map
]
389 m
.d
.comb
+= sub_bus
.addr
.eq(self
.bus
.addr
[:sub_bus
.addr_width
])
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
)
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
)
400 m
.d
.comb
+= self
.bus
.r_data
.eq(r_data_fanin
)