wishbone.bus: add Decoder.
[nmigen-soc.git] / nmigen_soc / csr / wishbone.py
1 from nmigen import *
2 from nmigen.utils import log2_int
3
4 from . import Interface as CSRInterface
5 from ..wishbone import Interface as WishboneInterface
6
7
8 __all__ = ["WishboneCSRBridge"]
9
10
11 class WishboneCSRBridge(Elaboratable):
12 """Wishbone to CSR bridge.
13
14 A bus bridge for accessing CSR registers from Wishbone. This bridge supports any Wishbone
15 data width greater or equal to CSR data width and performs appropriate address translation.
16
17 Latency
18 -------
19
20 Reads and writes always take ``self.data_width // csr_bus.data_width + 1`` cycles to complete,
21 regardless of the select inputs. Write side effects occur simultaneously with acknowledgement.
22
23 Parameters
24 ----------
25 csr_bus : :class:`..csr.Interface`
26 CSR bus driven by the bridge.
27 data_width : int or None
28 Wishbone bus data width. If not specified, defaults to ``csr_bus.data_width``.
29
30 Attributes
31 ----------
32 wb_bus : :class:`..wishbone.Interface`
33 Wishbone bus provided by the bridge.
34 """
35 def __init__(self, csr_bus, *, data_width=None):
36 if not isinstance(csr_bus, CSRInterface):
37 raise ValueError("CSR bus must be an instance of CSRInterface, not {!r}"
38 .format(csr_bus))
39 if csr_bus.data_width not in (8, 16, 32, 64):
40 raise ValueError("CSR bus data width must be one of 8, 16, 32, 64, not {!r}"
41 .format(csr_bus.data_width))
42 if data_width is None:
43 data_width = csr_bus.data_width
44
45 self.csr_bus = csr_bus
46 self.wb_bus = WishboneInterface(
47 addr_width=max(0, csr_bus.addr_width - log2_int(data_width // csr_bus.data_width)),
48 data_width=data_width,
49 granularity=csr_bus.data_width,
50 name="wb")
51
52 # Since granularity of the Wishbone interface matches the data width of the CSR bus,
53 # no width conversion is performed, even if the Wishbone data width is greater.
54 self.wb_bus.memory_map.add_window(self.csr_bus.memory_map)
55
56 def elaborate(self, platform):
57 csr_bus = self.csr_bus
58 wb_bus = self.wb_bus
59
60 m = Module()
61
62 cycle = Signal(range(len(wb_bus.sel) + 1))
63 m.d.comb += csr_bus.addr.eq(Cat(cycle[:log2_int(len(wb_bus.sel))], wb_bus.adr))
64
65 with m.If(wb_bus.cyc & wb_bus.stb):
66 with m.Switch(cycle):
67 def segment(index):
68 return slice(index * wb_bus.granularity, (index + 1) * wb_bus.granularity)
69
70 for index, sel_index in enumerate(wb_bus.sel):
71 with m.Case(index):
72 if index > 0:
73 # CSR reads are registered, and we need to re-register them.
74 m.d.sync += wb_bus.dat_r[segment(index - 1)].eq(csr_bus.r_data)
75 m.d.comb += csr_bus.r_stb.eq(sel_index & ~wb_bus.we)
76 m.d.comb += csr_bus.w_data.eq(wb_bus.dat_w[segment(index)])
77 m.d.comb += csr_bus.w_stb.eq(sel_index & wb_bus.we)
78 m.d.sync += cycle.eq(index + 1)
79
80 with m.Default():
81 m.d.sync += wb_bus.dat_r[segment(index)].eq(csr_bus.r_data)
82 m.d.sync += wb_bus.ack.eq(1)
83 m.d.sync += cycle.eq(0)
84
85 with m.Else():
86 m.d.sync += wb_bus.ack.eq(0)
87 m.d.sync += cycle.eq(0)
88
89 return m