2 from nmigen
import tracer
3 from nmigen
.utils
import log2_int
5 from nmigen_soc
import csr
, wishbone
6 from nmigen_soc
.memory
import MemoryMap
7 from nmigen_soc
.csr
.wishbone
import WishboneCSRBridge
13 __all__
= ["Peripheral", "CSRBank", "PeripheralBridge"]
17 """Wishbone peripheral.
19 A helper class to reduce the boilerplate needed to control a peripheral with a Wishbone interface.
20 It provides facilities for instantiating CSR registers, requesting windows to subordinate busses
21 and sending interrupt requests to the CPU.
23 The ``Peripheral`` class is not meant to be instantiated as-is, but rather as a base class for
30 class ExamplePeripheral(Peripheral, Elaboratable):
33 bank = self.csr_bank()
34 self._foo = bank.csr(8, "r")
35 self._bar = bank.csr(8, "w")
37 self._rdy = self.event(mode="rise")
39 self._bridge = self.bridge(data_width=32, granularity=8, alignment=2)
40 self.bus = self._bridge.bus
41 self.irq = self._bridge.irq
43 def elaborate(self, platform):
45 m.submodules.bridge = self._bridge
53 Name of this peripheral. If ``None`` (default) the name is inferred from the variable
54 name this peripheral is assigned to.
59 Name of the peripheral.
61 def __init__(self
, name
=None, src_loc_at
=1):
62 if name
is not None and not isinstance(name
, str):
63 raise TypeError("Name must be a string, not {!r}".format(name
))
64 self
.name
= name
or tracer
.get_var_name(depth
=2 + src_loc_at
).lstrip("_")
75 """Wishbone bus interface.
79 An instance of :class:`Interface`.
83 Raises :exn:`NotImplementedError` if the peripheral does not have a Wishbone bus.
86 raise NotImplementedError("Peripheral {!r} does not have a bus interface"
92 if not isinstance(bus
, wishbone
.Interface
):
93 raise TypeError("Bus interface must be an instance of wishbone.Interface, not {!r}"
99 """Interrupt request line.
103 An instance of :class:`IRQLine`.
107 Raises :exn:`NotImplementedError` if the peripheral does not have an IRQ line.
109 if self
._irq
is None:
110 raise NotImplementedError("Peripheral {!r} does not have an IRQ line"
116 if not isinstance(irq
, IRQLine
):
117 raise TypeError("IRQ line must be an instance of IRQLine, not {!r}"
121 def csr_bank(self
, *, addr
=None, alignment
=None):
122 """Request a CSR bank.
127 Address of the bank. If ``None``, the implicit next address will be used.
128 Otherwise, the exact specified address (which must be a multiple of
129 ``2 ** max(alignment, bridge_alignment)``) will be used.
130 alignment : int or None
131 Alignment of the bank. If not specified, the bridge alignment is used.
132 See :class:`nmigen_soc.csr.Multiplexer` for details.
136 An instance of :class:`CSRBank`.
138 bank
= CSRBank(name_prefix
=self
.name
)
139 self
._csr
_banks
.append((bank
, addr
, alignment
))
142 def window(self
, *, addr_width
, data_width
, granularity
=None, features
=frozenset(),
143 alignment
=0, addr
=None, sparse
=None):
144 """Request a window to a subordinate bus.
146 See :meth:`nmigen_soc.wishbone.Decoder.add` for details.
150 An instance of :class:`nmigen_soc.wishbone.Interface`.
152 window
= wishbone
.Interface(addr_width
=addr_width
, data_width
=data_width
,
153 granularity
=granularity
, features
=features
)
154 granularity_bits
= log2_int(data_width
// window
.granularity
)
155 window
.memory_map
= MemoryMap(addr_width
=addr_width
+ granularity_bits
,
156 data_width
=window
.granularity
, alignment
=alignment
)
157 self
._windows
.append((window
, addr
, sparse
))
160 def event(self
, *, mode
="level", name
=None, src_loc_at
=0):
161 """Request an event source.
163 See :class:`EventSource` for details.
167 An instance of :class:`EventSource`.
169 event
= EventSource(mode
=mode
, name
=name
, src_loc_at
=1 + src_loc_at
)
170 self
._events
.append(event
)
173 def bridge(self
, *, data_width
=8, granularity
=None, features
=frozenset(), alignment
=0):
174 """Request a bridge to the resources of the peripheral.
176 See :class:`PeripheralBridge` for details.
180 A :class:`PeripheralBridge` providing access to local resources.
182 return PeripheralBridge(self
, data_width
=data_width
, granularity
=granularity
,
183 features
=features
, alignment
=alignment
)
185 def iter_csr_banks(self
):
186 """Iterate requested CSR banks and their parameters.
190 A tuple ``bank, addr, alignment`` describing the bank and its parameters.
192 for bank
, addr
, alignment
in self
._csr
_banks
:
193 yield bank
, addr
, alignment
195 def iter_windows(self
):
196 """Iterate requested windows and their parameters.
200 A tuple ``window, addr, sparse`` descr
201 given to :meth:`Peripheral.window`.
203 for window
, addr
, sparse
in self
._windows
:
204 yield window
, addr
, sparse
206 def iter_events(self
):
207 """Iterate requested event sources.
211 An instance of :class:`EventSource`.
213 for event
in self
._events
:
218 """CSR register bank.
223 Name prefix of the bank registers.
225 def __init__(self
, *, name_prefix
=""):
226 self
._name
_prefix
= name_prefix
229 def csr(self
, width
, access
, *, addr
=None, alignment
=None, name
=None,
231 """Request a CSR register.
236 Width of the register. See :class:`nmigen_soc.csr.Element`.
237 access : :class:`Access`
238 Register access mode. See :class:`nmigen_soc.csr.Element`.
240 Address of the register. See :meth:`nmigen_soc.csr.Multiplexer.add`.
242 Register alignment. See :class:`nmigen_soc.csr.Multiplexer`.
244 Name of the register. If ``None`` (default) the name is inferred from the variable
245 name this register is assigned to.
249 An instance of :class:`nmigen_soc.csr.Element`.
251 if name
is not None and not isinstance(name
, str):
252 raise TypeError("Name must be a string, not {!r}".format(name
))
253 name
= name
or tracer
.get_var_name(depth
=2 + src_loc_at
).lstrip("_")
255 elem_name
= "{}_{}".format(self
._name
_prefix
, name
)
256 elem
= csr
.Element(width
, access
, name
=elem_name
)
257 self
._csr
_regs
.append((elem
, addr
, alignment
))
260 def iter_csr_regs(self
):
261 """Iterate requested CSR registers and their parameters.
265 A tuple ``elem, addr, alignment`` describing the register and its parameters.
267 for elem
, addr
, alignment
in self
._csr
_regs
:
268 yield elem
, addr
, alignment
271 class PeripheralBridge(Elaboratable
):
272 """Peripheral bridge.
274 A bridge providing access to the registers and windows of a peripheral, and support for
275 interrupt requests from its event sources.
277 Event managment is performed by an :class:`InterruptSource` submodule.
281 periph : :class:`Peripheral`
282 The peripheral whose resources are exposed by this bridge.
284 Data width. See :class:`nmigen_soc.wishbone.Interface`.
285 granularity : int or None
286 Granularity. See :class:`nmigen_soc.wishbone.Interface`.
288 Optional signal set. See :class:`nmigen_soc.wishbone.Interface`.
290 Resource alignment. See :class:`nmigen_soc.memory.MemoryMap`.
294 bus : :class:`nmigen_soc.wishbone.Interface`
295 Wishbone bus providing access to the resources of the peripheral.
296 irq : :class:`IRQLine`, out
297 Interrupt request. It is raised if any event source is enabled and has a pending
300 def __init__(self
, periph
, *, data_width
, granularity
, features
, alignment
):
301 if not isinstance(periph
, Peripheral
):
302 raise TypeError("Peripheral must be an instance of Peripheral, not {!r}"
305 self
._wb
_decoder
= wishbone
.Decoder(addr_width
=1, data_width
=data_width
,
306 granularity
=granularity
,
307 features
=features
, alignment
=alignment
)
311 for bank
, bank_addr
, bank_alignment
in periph
.iter_csr_banks():
312 if bank_alignment
is None:
313 bank_alignment
= alignment
314 csr_mux
= csr
.Multiplexer(addr_width
=1, data_width
=8, alignment
=bank_alignment
)
315 for elem
, elem_addr
, elem_alignment
in bank
.iter_csr_regs():
316 if elem_alignment
is None:
317 elem_alignment
= alignment
318 csr_mux
.add(elem
, addr
=elem_addr
, alignment
=elem_alignment
, extend
=True)
320 csr_bridge
= WishboneCSRBridge(csr_mux
.bus
, data_width
=data_width
)
321 self
._wb
_decoder
.add(csr_bridge
.wb_bus
, addr
=bank_addr
, extend
=True)
322 self
._csr
_subs
.append((csr_mux
, csr_bridge
))
324 for window
, window_addr
, window_sparse
in periph
.iter_windows():
325 self
._wb
_decoder
.add(window
, addr
=window_addr
, sparse
=window_sparse
, extend
=True)
327 events
= list(periph
.iter_events())
329 self
._int
_src
= InterruptSource(events
, name
="{}_ev".format(periph
.name
))
330 self
.irq
= self
._int
_src
.irq
332 csr_mux
= csr
.Multiplexer(addr_width
=1, data_width
=8, alignment
=alignment
)
333 csr_mux
.add(self
._int
_src
.status
, extend
=True)
334 csr_mux
.add(self
._int
_src
.pending
, extend
=True)
335 csr_mux
.add(self
._int
_src
.enable
, extend
=True)
337 csr_bridge
= WishboneCSRBridge(csr_mux
.bus
, data_width
=data_width
)
338 self
._wb
_decoder
.add(csr_bridge
.wb_bus
, extend
=True)
339 self
._csr
_subs
.append((csr_mux
, csr_bridge
))
344 self
.bus
= self
._wb
_decoder
.bus
346 def elaborate(self
, platform
):
349 for i
, (csr_mux
, csr_bridge
) in enumerate(self
._csr
_subs
):
350 m
.submodules
[ "csr_mux_{}".format(i
)] = csr_mux
351 m
.submodules
["csr_bridge_{}".format(i
)] = csr_bridge
353 if self
._int
_src
is not None:
354 m
.submodules
._int
_src
= self
._int
_src
356 m
.submodules
.wb_decoder
= self
._wb
_decoder