more 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
39 def __init__(self, csr_bus, *, data_width=None):
40 if not isinstance(csr_bus, CSRInterface):
41 raise ValueError("CSR bus must be an instance of CSRInterface, "
42 "not {!r}" .format(csr_bus))
43 if csr_bus.data_width not in (8, 16, 32, 64):
44 raise ValueError("CSR bus data width must be one of 8, 16, 32, 64, "
45 "not {!r}" .format(csr_bus.data_width))
46 if data_width is None:
47 data_width = csr_bus.data_width
48
49 self.csr_bus = csr_bus
50 self.wb_bus = WishboneInterface(
51 addr_width=max(
52 0,
53 csr_bus.addr_width -
54 log2_int(
55 data_width //
56 csr_bus.data_width)),
57 data_width=data_width,
58 granularity=csr_bus.data_width,
59 name="wb")
60
61 # Since granularity of the Wishbone interface matches the data
62 # width of the CSR bus, no width conversion is performed, even
63 # if the Wishbone data width is greater.
64 self.wb_bus.memory_map.add_window(self.csr_bus.memory_map)
65
66 def elaborate(self, platform):
67 csr_bus = self.csr_bus
68 wb_bus = self.wb_bus
69
70 m = Module()
71
72 cycle = Signal(range(len(wb_bus.sel) + 1))
73 m.d.comb += csr_bus.addr.eq(
74 Cat(cycle[:log2_int(len(wb_bus.sel))], wb_bus.adr))
75
76 with m.If(wb_bus.cyc & wb_bus.stb):
77 with m.Switch(cycle):
78 def segment(index):
79 return slice(index * wb_bus.granularity,
80 (index + 1) * wb_bus.granularity)
81
82 for index, sel_index in enumerate(wb_bus.sel):
83 with m.Case(index):
84 if index > 0:
85 # CSR reads are registered, and we need to
86 # re-register them.
87 m.d.sync += wb_bus.dat_r[segment(
88 index - 1)].eq(csr_bus.r_data)
89 m.d.comb += csr_bus.r_stb.eq(sel_index & ~wb_bus.we)
90 m.d.comb += csr_bus.w_data.eq(
91 wb_bus.dat_w[segment(index)])
92 m.d.comb += csr_bus.w_stb.eq(sel_index & wb_bus.we)
93 m.d.sync += cycle.eq(index + 1)
94
95 with m.Default():
96 m.d.sync += wb_bus.dat_r[segment(index)].eq(csr_bus.r_data)
97 m.d.sync += wb_bus.ack.eq(1)
98 m.d.sync += cycle.eq(0)
99
100 with m.Else():
101 m.d.sync += wb_bus.ack.eq(0)
102 m.d.sync += cycle.eq(0)
103
104 return m