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