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
, *, name
=None, addr
=None, alignment
=None):
122 """Request a CSR bank.
129 Address of the bank. If ``None``, the implicit next address will be used.
130 Otherwise, the exact specified address (which must be a multiple of
131 ``2 ** max(alignment, bridge_alignment)``) will be used.
132 alignment : int or None
133 Alignment of the bank. If not specified, the bridge alignment is used.
134 See :class:`nmigen_soc.csr.Multiplexer` for details.
138 An instance of :class:`CSRBank`.
140 bank
= CSRBank(name
=name
)
141 self
._csr
_banks
.append((bank
, addr
, alignment
))
144 def window(self
, *, addr_width
, data_width
, granularity
=None, features
=frozenset(),
145 name
=None, addr
=None, sparse
=None):
146 """Request a window to a subordinate bus.
148 See :meth:`nmigen_soc.wishbone.Decoder.add` for details.
152 An instance of :class:`nmigen_soc.wishbone.Interface`.
154 window
= wishbone
.Interface(addr_width
=addr_width
, data_width
=data_width
,
155 granularity
=granularity
, features
=features
, name
=name
)
156 self
._windows
.append((window
, addr
, sparse
))
159 def event(self
, *, mode
="level", name
=None, src_loc_at
=0):
160 """Request an event source.
162 See :class:`EventSource` for details.
166 An instance of :class:`EventSource`.
168 event
= EventSource(mode
=mode
, name
=name
, src_loc_at
=1 + src_loc_at
)
169 self
._events
.append(event
)
172 def bridge(self
, *, data_width
=8, granularity
=None, features
=frozenset(), alignment
=0):
173 """Request a bridge to the resources of the peripheral.
175 See :class:`PeripheralBridge` for details.
179 A :class:`PeripheralBridge` providing access to local resources.
181 return PeripheralBridge(self
, data_width
=data_width
, granularity
=granularity
,
182 features
=features
, alignment
=alignment
)
184 def iter_csr_banks(self
):
185 """Iterate requested CSR banks and their parameters.
189 A tuple ``bank, addr, alignment`` describing the bank and its parameters.
191 for bank
, addr
, alignment
in self
._csr
_banks
:
192 yield bank
, addr
, alignment
194 def iter_windows(self
):
195 """Iterate requested windows and their parameters.
199 A tuple ``window, addr, sparse`` descr
200 given to :meth:`Peripheral.window`.
202 for window
, addr
, sparse
in self
._windows
:
203 yield window
, addr
, sparse
205 def iter_events(self
):
206 """Iterate requested event sources.
210 An instance of :class:`EventSource`.
212 for event
in self
._events
:
217 """CSR register bank.
222 Optional. Name prefix of the bank registers.
224 def __init__(self
, *, name
=None):
225 if name
is not None and not isinstance(name
, str):
226 raise TypeError("Name must be a string, not {!r}".format(name
))
231 def csr(self
, width
, access
, *, addr
=None, alignment
=None, name
=None,
233 """Request a CSR register.
238 Width of the register. See :class:`nmigen_soc.csr.Element`.
239 access : :class:`Access`
240 Register access mode. See :class:`nmigen_soc.csr.Element`.
242 Address of the register. See :meth:`nmigen_soc.csr.Multiplexer.add`.
244 Register alignment. See :class:`nmigen_soc.csr.Multiplexer`.
246 Name of the register. If ``None`` (default) the name is inferred from the variable
247 name this register is assigned to.
251 An instance of :class:`nmigen_soc.csr.Element`.
253 if name
is not None and not isinstance(name
, str):
254 raise TypeError("Name must be a string, not {!r}".format(name
))
255 name
= name
or tracer
.get_var_name(depth
=2 + src_loc_at
).lstrip("_")
257 if any(elem
.name
== name
for (elem
, _
, _
) in self
._csr
_regs
):
258 raise Exception("CSR \"{}\" has already been defined".format(name
))
259 elem
= csr
.Element(width
, access
, name
=name
)
260 self
._csr
_regs
.append((elem
, addr
, alignment
))
263 def iter_csr_regs(self
):
264 """Iterate requested CSR registers and their parameters.
268 A tuple ``elem, addr, alignment`` describing the register and its parameters.
270 for elem
, addr
, alignment
in self
._csr
_regs
:
271 yield elem
, addr
, alignment
274 class PeripheralBridge(Elaboratable
):
275 """Peripheral bridge.
277 A bridge providing access to the registers and windows of a peripheral, and support for
278 interrupt requests from its event sources.
280 Event managment is performed by an :class:`InterruptSource` submodule.
284 periph : :class:`Peripheral`
285 The peripheral whose resources are exposed by this bridge.
287 Data width. See :class:`nmigen_soc.wishbone.Interface`.
288 granularity : int or None
289 Granularity. See :class:`nmigen_soc.wishbone.Interface`.
291 Optional signal set. See :class:`nmigen_soc.wishbone.Interface`.
293 Resource alignment. See :class:`nmigen_soc.memory.MemoryMap`.
297 bus : :class:`nmigen_soc.wishbone.Interface`
298 Wishbone bus providing access to the resources of the peripheral.
299 irq : :class:`IRQLine`, out
300 Interrupt request. It is raised if any event source is enabled and has a pending
303 def __init__(self
, periph
, *, data_width
, granularity
, features
, alignment
):
304 if not isinstance(periph
, Peripheral
):
305 raise TypeError("Peripheral must be an instance of Peripheral, not {!r}"
308 self
._wb
_decoder
= wishbone
.Decoder(addr_width
=1, data_width
=data_width
,
309 granularity
=granularity
,
310 features
=features
, alignment
=alignment
,
315 for bank
, bank_addr
, bank_alignment
in periph
.iter_csr_banks():
316 if bank_alignment
is None:
317 bank_alignment
= alignment
318 csr_mux
= csr
.Multiplexer(
319 addr_width
=1, data_width
=granularity
, alignment
=bank_alignment
,
322 for elem
, elem_addr
, elem_alignment
in bank
.iter_csr_regs():
323 if elem_alignment
is None:
324 elem_alignment
= alignment
325 csr_mux
.add(elem
, addr
=elem_addr
, alignment
=elem_alignment
, extend
=True)
327 csr_bridge
= WishboneCSRBridge(csr_mux
.bus
, data_width
=data_width
)
328 self
._wb
_decoder
.add(csr_bridge
.wb_bus
, addr
=bank_addr
, extend
=True)
329 self
._csr
_subs
.append((csr_mux
, csr_bridge
))
331 for window
, window_addr
, window_sparse
in periph
.iter_windows():
332 self
._wb
_decoder
.add(window
, addr
=window_addr
, sparse
=window_sparse
, extend
=True)
334 events
= list(periph
.iter_events())
336 self
._int
_src
= InterruptSource(events
, name
=periph
.name
)
337 self
.irq
= self
._int
_src
.irq
339 csr_mux
= csr
.Multiplexer(addr_width
=1, data_width
=8, alignment
=alignment
, name
="ev")
340 csr_mux
.add(self
._int
_src
.status
, extend
=True)
341 csr_mux
.add(self
._int
_src
.pending
, extend
=True)
342 csr_mux
.add(self
._int
_src
.enable
, extend
=True)
344 csr_bridge
= WishboneCSRBridge(csr_mux
.bus
, data_width
=data_width
)
345 self
._wb
_decoder
.add(csr_bridge
.wb_bus
, extend
=True)
346 self
._csr
_subs
.append((csr_mux
, csr_bridge
))
351 self
.bus
= self
._wb
_decoder
.bus
353 def elaborate(self
, platform
):
356 for i
, (csr_mux
, csr_bridge
) in enumerate(self
._csr
_subs
):
357 m
.submodules
[ "csr_mux_{}".format(i
)] = csr_mux
358 m
.submodules
["csr_bridge_{}".format(i
)] = csr_bridge
360 if self
._int
_src
is not None:
361 m
.submodules
._int
_src
= self
._int
_src
363 m
.submodules
.wb_decoder
= self
._wb
_decoder