wishbone.bus: add Decoder.
[nmigen-soc.git] / nmigen_soc / wishbone / bus.py
1 from enum import Enum
2 from nmigen import *
3 from nmigen.hdl.rec import Direction
4 from nmigen.utils import log2_int
5
6 from ..memory import MemoryMap
7
8
9 __all__ = ["CycleType", "BurstTypeExt", "Interface", "Decoder"]
10
11
12 class CycleType(Enum):
13 """Wishbone Registered Feedback cycle type."""
14 CLASSIC = 0b000
15 CONST_BURST = 0b001
16 INCR_BURST = 0b010
17 END_OF_BURST = 0b111
18
19
20 class BurstTypeExt(Enum):
21 """Wishbone Registered Feedback burst type extension."""
22 LINEAR = 0b00
23 WRAP_4 = 0b01
24 WRAP_8 = 0b10
25 WRAP_16 = 0b11
26
27
28 class Interface(Record):
29 """Wishbone interface.
30
31 See the `Wishbone specification <https://opencores.org/howto/wishbone>`_ for description
32 of the Wishbone signals. The ``RST_I`` and ``CLK_I`` signals are provided as a part of
33 the clock domain that drives the interface.
34
35 Note that the data width of the underlying memory map of the interface is equal to port
36 granularity, not port size. If port granularity is less than port size, then the address width
37 of the underlying memory map is extended to reflect that.
38
39 Parameters
40 ----------
41 addr_width : int
42 Width of the address signal.
43 data_width : int
44 Width of the data signals ("port size" in Wishbone terminology).
45 One of 8, 16, 32, 64.
46 granularity : int
47 Granularity of select signals ("port granularity" in Wishbone terminology).
48 One of 8, 16, 32, 64.
49 features : iter(str)
50 Selects the optional signals that will be a part of this interface.
51 alignment : int
52 Resource and window alignment. See :class:`MemoryMap`.
53 name : str
54 Name of the underlying record.
55
56 Attributes
57 ----------
58 The correspondence between the nMigen-SoC signals and the Wishbone signals changes depending
59 on whether the interface acts as an initiator or a target.
60
61 adr : Signal(addr_width)
62 Corresponds to Wishbone signal ``ADR_O`` (initiator) or ``ADR_I`` (target).
63 dat_w : Signal(data_width)
64 Corresponds to Wishbone signal ``DAT_O`` (initiator) or ``DAT_I`` (target).
65 dat_r : Signal(data_width)
66 Corresponds to Wishbone signal ``DAT_I`` (initiator) or ``DAT_O`` (target).
67 sel : Signal(data_width // granularity)
68 Corresponds to Wishbone signal ``SEL_O`` (initiator) or ``SEL_I`` (target).
69 cyc : Signal()
70 Corresponds to Wishbone signal ``CYC_O`` (initiator) or ``CYC_I`` (target).
71 stb : Signal()
72 Corresponds to Wishbone signal ``STB_O`` (initiator) or ``STB_I`` (target).
73 we : Signal()
74 Corresponds to Wishbone signal ``WE_O`` (initiator) or ``WE_I`` (target).
75 ack : Signal()
76 Corresponds to Wishbone signal ``ACK_I`` (initiator) or ``ACK_O`` (target).
77 err : Signal()
78 Optional. Corresponds to Wishbone signal ``ERR_I`` (initiator) or ``ERR_O`` (target).
79 rty : Signal()
80 Optional. Corresponds to Wishbone signal ``RTY_I`` (initiator) or ``RTY_O`` (target).
81 stall : Signal()
82 Optional. Corresponds to Wishbone signal ``STALL_I`` (initiator) or ``STALL_O`` (target).
83 lock : Signal()
84 Optional. Corresponds to Wishbone signal ``LOCK_O`` (initiator) or ``LOCK_I`` (target).
85 cti : Signal()
86 Optional. Corresponds to Wishbone signal ``CTI_O`` (initiator) or ``CTI_I`` (target).
87 bte : Signal()
88 Optional. Corresponds to Wishbone signal ``BTE_O`` (initiator) or ``BTE_I`` (target).
89 """
90 def __init__(self, *, addr_width, data_width, granularity=None, features=frozenset(),
91 alignment=0, name=None):
92 if not isinstance(addr_width, int) or addr_width < 0:
93 raise ValueError("Address width must be a non-negative integer, not {!r}"
94 .format(addr_width))
95 if data_width not in (8, 16, 32, 64):
96 raise ValueError("Data width must be one of 8, 16, 32, 64, not {!r}"
97 .format(data_width))
98 if granularity is None:
99 granularity = data_width
100 elif granularity not in (8, 16, 32, 64):
101 raise ValueError("Granularity must be one of 8, 16, 32, 64, not {!r}"
102 .format(granularity))
103 if granularity > data_width:
104 raise ValueError("Granularity {} may not be greater than data width {}"
105 .format(granularity, data_width))
106 self.addr_width = addr_width
107 self.data_width = data_width
108 self.granularity = granularity
109 granularity_bits = log2_int(data_width // granularity)
110 self.memory_map = MemoryMap(addr_width=max(1, addr_width + granularity_bits),
111 data_width=data_width >> granularity_bits,
112 alignment=alignment)
113
114 features = set(features)
115 unknown = features - {"rty", "err", "stall", "lock", "cti", "bte"}
116 if unknown:
117 raise ValueError("Optional signal(s) {} are not supported"
118 .format(", ".join(map(repr, unknown))))
119 layout = [
120 ("adr", addr_width, Direction.FANOUT),
121 ("dat_w", data_width, Direction.FANOUT),
122 ("dat_r", data_width, Direction.FANIN),
123 ("sel", data_width // granularity, Direction.FANOUT),
124 ("cyc", 1, Direction.FANOUT),
125 ("stb", 1, Direction.FANOUT),
126 ("we", 1, Direction.FANOUT),
127 ("ack", 1, Direction.FANIN),
128 ]
129 if "err" in features:
130 layout += [("err", 1, Direction.FANIN)]
131 if "rty" in features:
132 layout += [("rty", 1, Direction.FANIN)]
133 if "stall" in features:
134 layout += [("stall", 1, Direction.FANIN)]
135 if "lock" in features:
136 layout += [("lock", 1, Direction.FANOUT)]
137 if "cti" in features:
138 layout += [("cti", CycleType, Direction.FANOUT)]
139 if "bte" in features:
140 layout += [("bte", BurstTypeExt, Direction.FANOUT)]
141 super().__init__(layout, name=name, src_loc_at=1)
142
143
144 class Decoder(Elaboratable):
145 """Wishbone bus decoder.
146
147 An address decoder for subordinate Wishbone buses.
148
149 Parameters
150 ----------
151 addr_width : int
152 Address width. See :class:`Interface`.
153 data_width : int
154 Data width. See :class:`Interface`.
155 granularity : int
156 Granularity. See :class:`Interface`
157 features : iter(str)
158 Optional signal set. See :class:`Interface`.
159 alignment : int
160 Window alignment. See :class:`Interface`.
161
162 Attributes
163 ----------
164 bus : :class:`Interface`
165 CSR bus providing access to subordinate buses.
166 """
167 def __init__(self, *, addr_width, data_width, granularity=None, features=frozenset(),
168 alignment=0):
169 self.bus = Interface(addr_width=addr_width, data_width=data_width,
170 granularity=granularity, features=features,
171 alignment=alignment)
172 self._map = self.bus.memory_map
173 self._subs = dict()
174
175 def align_to(self, alignment):
176 """Align the implicit address of the next window.
177
178 See :meth:`MemoryMap.align_to` for details.
179 """
180 return self._map.align_to(alignment)
181
182 def add(self, sub_bus, *, addr=None, sparse=False):
183 """Add a window to a subordinate bus.
184
185 The decoder can perform either sparse or dense address translation. If dense address
186 translation is used (the default), the subordinate bus must have the same data width as
187 the decoder; the window will be contiguous. If sparse address translation is used,
188 the subordinate bus may have data width less than the data width of the decoder;
189 the window may be discontiguous. In either case, the granularity of the subordinate bus
190 must be equal to or less than the granularity of the decoder.
191
192 See :meth:`MemoryMap.add_resource` for details.
193 """
194 if not isinstance(sub_bus, Interface):
195 raise TypeError("Subordinate bus must be an instance of wishbone.Interface, not {!r}"
196 .format(sub_bus))
197 if sub_bus.granularity > self.bus.granularity:
198 raise ValueError("Subordinate bus has granularity {}, which is greater than the "
199 "decoder granularity {}"
200 .format(sub_bus.granularity, self.bus.granularity))
201 if not sparse:
202 if sub_bus.data_width != self.bus.data_width:
203 raise ValueError("Subordinate bus has data width {}, which is not the same as "
204 "decoder data width {} (required for dense address translation)"
205 .format(sub_bus.data_width, self.bus.data_width))
206 else:
207 if sub_bus.granularity != sub_bus.data_width:
208 raise ValueError("Subordinate bus has data width {}, which is not the same as "
209 "subordinate bus granularity {} (required for sparse address "
210 "translation)"
211 .format(sub_bus.data_width, sub_bus.granularity))
212 for opt_output in {"err", "rty", "stall"}:
213 if hasattr(sub_bus, opt_output) and not hasattr(self.bus, opt_output):
214 raise ValueError("Subordinate bus has optional output {!r}, but the decoder "
215 "does not have a corresponding input"
216 .format(opt_output))
217
218 self._subs[sub_bus.memory_map] = sub_bus
219 return self._map.add_window(sub_bus.memory_map, addr=addr, sparse=sparse)
220
221 def elaborate(self, platform):
222 m = Module()
223
224 ack_fanin = 0
225 err_fanin = 0
226 rty_fanin = 0
227 stall_fanin = 0
228
229 with m.Switch(self.bus.adr):
230 for sub_map, (sub_pat, sub_ratio) in self._map.window_patterns():
231 sub_bus = self._subs[sub_map]
232
233 m.d.comb += [
234 sub_bus.adr.eq(self.bus.adr << log2_int(sub_ratio)),
235 sub_bus.dat_w.eq(self.bus.dat_w),
236 sub_bus.sel.eq(Cat(Repl(sel, sub_ratio) for sel in self.bus.sel)),
237 sub_bus.we.eq(self.bus.we),
238 sub_bus.stb.eq(self.bus.stb),
239 ]
240 if hasattr(sub_bus, "lock"):
241 m.d.comb += sub_bus.lock.eq(getattr(self.bus, "lock", 0))
242 if hasattr(sub_bus, "cti"):
243 m.d.comb += sub_bus.cti.eq(getattr(self.bus, "cti", CycleType.CLASSIC))
244 if hasattr(sub_bus, "bte"):
245 m.d.comb += sub_bus.bte.eq(getattr(self.bus, "bte", BurstTypeExt.LINEAR))
246
247 with m.Case(sub_pat[:-log2_int(self.bus.data_width // self.bus.granularity)]):
248 m.d.comb += [
249 sub_bus.cyc.eq(self.bus.cyc),
250 self.bus.dat_r.eq(sub_bus.dat_r),
251 ]
252 ack_fanin |= sub_bus.ack
253 if hasattr(sub_bus, "err"):
254 err_fanin |= sub_bus.err
255 if hasattr(sub_bus, "rty"):
256 rty_fanin |= sub_bus.rty
257 if hasattr(sub_bus, "stall"):
258 stall_fanin |= sub_bus.stall
259
260 m.d.comb += self.bus.ack.eq(ack_fanin)
261 if hasattr(self.bus, "err"):
262 m.d.comb += self.bus.err.eq(err_fanin)
263 if hasattr(self.bus, "rty"):
264 m.d.comb += self.bus.rty.eq(rty_fanin)
265 if hasattr(self.bus, "stall"):
266 m.d.comb += self.bus.stall.eq(stall_fanin)
267
268 return m