ec25bbaeae405f666353cd392ac46085167049bf
[litex.git] / litex / soc / interconnect / axi.py
1 # This file is Copyright (c) 2018-2019 Florent Kermarrec <florent@enjoy-digital.fr>
2 # This file is Copyright (c) 2020 Antmicro <www.antmicro.com>
3 # License: BSD
4
5 """AXI4 Full/Lite support for LiteX"""
6
7 from migen import *
8 from migen.genlib import roundrobin
9 from migen.genlib.misc import split, displacer, chooser, WaitTimer
10
11 from litex.soc.interconnect import stream
12 from litex.build.generic_platform import *
13
14 from litex.soc.interconnect import csr_bus
15
16 # AXI Definition -----------------------------------------------------------------------------------
17
18 BURST_FIXED = 0b00
19 BURST_INCR = 0b01
20 BURST_WRAP = 0b10
21 BURST_RESERVED = 0b11
22
23 RESP_OKAY = 0b00
24 RESP_EXOKAY = 0b01
25 RESP_SLVERR = 0b10
26 RESP_DECERR = 0b11
27
28 def ax_description(address_width, id_width):
29 return [
30 ("addr", address_width),
31 ("burst", 2), # Burst type
32 ("len", 8), # Number of data (-1) transfers (up to 256)
33 ("size", 4), # Number of bytes (-1) of each data transfer (up to 1024 bits)
34 ("lock", 2), # *
35 ("prot", 3), # *
36 ("cache", 4), # *
37 ("qos", 4), # *
38 ("id", id_width)
39 ]
40 # * present for interconnect with others cores but not used by LiteX.
41
42 def w_description(data_width, id_width):
43 return [
44 ("data", data_width),
45 ("strb", data_width//8),
46 ("id", id_width)
47 ]
48
49 def b_description(id_width):
50 return [
51 ("resp", 2),
52 ("id", id_width)
53 ]
54
55 def r_description(data_width, id_width):
56 return [
57 ("resp", 2),
58 ("data", data_width),
59 ("id", id_width)
60 ]
61
62 def _connect_axi(master, slave, keep=None, omit=None):
63 channel_modes = {
64 "aw": "master",
65 "w" : "master",
66 "b" : "slave",
67 "ar": "master",
68 "r" : "slave",
69 }
70 r = []
71 for channel, mode in channel_modes.items():
72 if mode == "master":
73 m, s = getattr(master, channel), getattr(slave, channel)
74 else:
75 s, m = getattr(master, channel), getattr(slave, channel)
76 r.extend(m.connect(s, keep=keep, omit=omit))
77 return r
78
79 def _axi_layout_flat(axi):
80 # yields tuples (channel, name, direction)
81 def get_dir(channel, direction):
82 if channel in ["b", "r"]:
83 return {DIR_M_TO_S: DIR_S_TO_M, DIR_S_TO_M: DIR_M_TO_S}[direction]
84 return direction
85 for ch in ["aw", "w", "b", "ar", "r"]:
86 channel = getattr(axi, ch)
87 for group in channel.layout:
88 if len(group) == 3:
89 name, _, direction = group
90 yield ch, name, get_dir(ch, direction)
91 else:
92 _, subgroups = group
93 for subgroup in subgroups:
94 name, _, direction = subgroup
95 yield ch, name, get_dir(ch, direction)
96
97 class AXIInterface:
98 def __init__(self, data_width=32, address_width=32, id_width=1, clock_domain="sys"):
99 self.data_width = data_width
100 self.address_width = address_width
101 self.id_width = id_width
102 self.clock_domain = clock_domain
103
104 self.aw = stream.Endpoint(ax_description(address_width, id_width))
105 self.w = stream.Endpoint(w_description(data_width, id_width))
106 self.b = stream.Endpoint(b_description(id_width))
107 self.ar = stream.Endpoint(ax_description(address_width, id_width))
108 self.r = stream.Endpoint(r_description(data_width, id_width))
109
110 def connect(self, slave, **kwargs):
111 return _connect_axi(self, slave, **kwargs)
112
113 def layout_flat(self):
114 return list(_axi_layout_flat(self))
115
116 # AXI Lite Definition ------------------------------------------------------------------------------
117
118 def ax_lite_description(address_width):
119 return [("addr", address_width)]
120
121 def w_lite_description(data_width):
122 return [
123 ("data", data_width),
124 ("strb", data_width//8)
125 ]
126
127 def b_lite_description():
128 return [("resp", 2)]
129
130 def r_lite_description(data_width):
131 return [
132 ("resp", 2),
133 ("data", data_width)
134 ]
135
136 class AXILiteInterface:
137 def __init__(self, data_width=32, address_width=32, clock_domain="sys", name=None):
138 self.data_width = data_width
139 self.address_width = address_width
140 self.clock_domain = clock_domain
141
142 self.aw = stream.Endpoint(ax_lite_description(address_width), name=name)
143 self.w = stream.Endpoint(w_lite_description(data_width), name=name)
144 self.b = stream.Endpoint(b_lite_description(), name=name)
145 self.ar = stream.Endpoint(ax_lite_description(address_width), name=name)
146 self.r = stream.Endpoint(r_lite_description(data_width), name=name)
147
148 def get_ios(self, bus_name="wb"):
149 subsignals = []
150 for channel in ["aw", "w", "b", "ar", "r"]:
151 for name in ["valid", "ready"]:
152 subsignals.append(Subsignal(channel + name, Pins(1)))
153 for name, width in getattr(self, channel).description.payload_layout:
154 subsignals.append(Subsignal(channel + name, Pins(width)))
155 ios = [(bus_name , 0) + tuple(subsignals)]
156 return ios
157
158 def connect_to_pads(self, pads, mode="master"):
159 assert mode in ["slave", "master"]
160 r = []
161 def swap_mode(mode): return "master" if mode == "slave" else "slave"
162 channel_modes = {
163 "aw": mode,
164 "w" : mode,
165 "b" : swap_mode(mode),
166 "ar": mode,
167 "r" : swap_mode(mode),
168 }
169 for channel, mode in channel_modes.items():
170 for name, width in [("valid", 1)] + getattr(self, channel).description.payload_layout:
171 sig = getattr(getattr(self, channel), name)
172 pad = getattr(pads, channel + name)
173 if mode == "master":
174 r.append(pad.eq(sig))
175 else:
176 r.append(sig.eq(pad))
177 for name, width in [("ready", 1)]:
178 sig = getattr(getattr(self, channel), name)
179 pad = getattr(pads, channel + name)
180 if mode == "master":
181 r.append(sig.eq(pad))
182 else:
183 r.append(pad.eq(sig))
184 return r
185
186 def connect(self, slave, **kwargs):
187 return _connect_axi(self, slave, **kwargs)
188
189 def layout_flat(self):
190 return list(_axi_layout_flat(self))
191
192 def write(self, addr, data, strb=None):
193 if strb is None:
194 strb = 2**len(self.w.strb) - 1
195 # aw + w
196 yield self.aw.valid.eq(1)
197 yield self.aw.addr.eq(addr)
198 yield self.w.data.eq(data)
199 yield self.w.valid.eq(1)
200 yield self.w.strb.eq(strb)
201 yield
202 while not (yield self.aw.ready):
203 yield
204 yield self.aw.valid.eq(0)
205 yield self.aw.addr.eq(0)
206 while not (yield self.w.ready):
207 yield
208 yield self.w.valid.eq(0)
209 yield self.w.strb.eq(0)
210 # b
211 yield self.b.ready.eq(1)
212 while not (yield self.b.valid):
213 yield
214 resp = (yield self.b.resp)
215 yield self.b.ready.eq(0)
216 return resp
217
218 def read(self, addr):
219 # ar
220 yield self.ar.valid.eq(1)
221 yield self.ar.addr.eq(addr)
222 yield
223 while not (yield self.ar.ready):
224 yield
225 yield self.ar.valid.eq(0)
226 # r
227 yield self.r.ready.eq(1)
228 while not (yield self.r.valid):
229 yield
230 data = (yield self.r.data)
231 resp = (yield self.r.resp)
232 yield self.r.ready.eq(0)
233 return (data, resp)
234
235 # AXI Stream Definition ----------------------------------------------------------------------------
236
237 class AXIStreamInterface(stream.Endpoint):
238 def __init__(self, data_width=32, user_width=0):
239 self.data_width = data_width
240 self.user_width = user_width
241 axi_layout = [("data", data_width)]
242 if self.user_width:
243 axi_layout += [("user", user_width)]
244 stream.Endpoint.__init__(self, axi_layout)
245
246 def get_ios(self, bus_name="axi"):
247 subsignals = [
248 Subsignal("tvalid", Pins(1)),
249 Subsignal("tlast", Pins(1)),
250 Subsignal("tready", Pins(1)),
251 Subsignal("tdata", Pins(self.data_width)),
252 ]
253 if self.user_width:
254 subsignals += [Subsignal("tuser", Pins(self.user_width))]
255 ios = [(bus_name , 0) + tuple(subsignals)]
256 return ios
257
258 def connect_to_pads(self, pads, mode="master"):
259 assert mode in ["slave", "master"]
260 r = []
261 if mode == "master":
262 r.append(pads.tvalid.eq(self.valid))
263 r.append(self.ready.eq(pads.tready))
264 r.append(pads.tlast.eq(self.last))
265 r.append(pads.tdata.eq(self.data))
266 if self.user_width:
267 r.append(pads.tuser.eq(self.user))
268 if mode == "slave":
269 r.append(self.valid.eq(pads.tvalid))
270 r.append(pads.tready.eq(self.ready))
271 r.append(self.last.eq(pads.tlast))
272 r.append(self.data.eq(pads.tdata))
273 if self.user_width:
274 r.append(self.user.eq(pads.tuser))
275 return r
276
277 # AXI Bursts to Beats ------------------------------------------------------------------------------
278
279 class AXIBurst2Beat(Module):
280 def __init__(self, ax_burst, ax_beat, capabilities={BURST_FIXED, BURST_INCR, BURST_WRAP}):
281 assert BURST_FIXED in capabilities
282
283 # # #
284
285 beat_count = Signal(8)
286 beat_size = Signal(8 + 4)
287 beat_offset = Signal(8 + 4)
288 beat_wrap = Signal(8 + 4)
289
290 # compute parameters
291 self.comb += beat_size.eq(1 << ax_burst.size)
292 self.comb += beat_wrap.eq(ax_burst.len << ax_burst.size)
293
294 # combinatorial logic
295 self.comb += [
296 ax_beat.valid.eq(ax_burst.valid | ~ax_beat.first),
297 ax_beat.first.eq(beat_count == 0),
298 ax_beat.last.eq(beat_count == ax_burst.len),
299 ax_beat.addr.eq(ax_burst.addr + beat_offset),
300 ax_beat.id.eq(ax_burst.id),
301 If(ax_beat.ready,
302 If(ax_beat.last,
303 ax_burst.ready.eq(1)
304 )
305 )
306 ]
307
308 # synchronous logic
309 self.sync += [
310 If(ax_beat.valid & ax_beat.ready,
311 If(ax_beat.last,
312 beat_count.eq(0),
313 beat_offset.eq(0)
314 ).Else(
315 beat_count.eq(beat_count + 1),
316 If(((ax_burst.burst == BURST_INCR) & (BURST_INCR in capabilities)) |
317 ((ax_burst.burst == BURST_WRAP) & (BURST_WRAP in capabilities)),
318 beat_offset.eq(beat_offset + beat_size)
319 )
320 ),
321 If((ax_burst.burst == BURST_WRAP) & (BURST_WRAP in capabilities),
322 If(beat_offset == beat_wrap,
323 beat_offset.eq(0)
324 )
325 )
326 )
327 ]
328
329
330 # AXI to AXI Lite ----------------------------------------------------------------------------------
331
332 class AXI2AXILite(Module):
333 # Note: Since this AXI bridge will mostly be used to target buses that are not supporting
334 # simultaneous writes/reads, to reduce ressource usage the AXIBurst2Beat module is shared
335 # between writes/reads.
336 def __init__(self, axi, axi_lite):
337 assert axi.data_width == axi_lite.data_width
338 assert axi.address_width == axi_lite.address_width
339
340 ax_buffer = stream.Buffer(ax_description(axi.address_width, axi.id_width))
341 ax_burst = stream.Endpoint(ax_description(axi.address_width, axi.id_width))
342 ax_beat = stream.Endpoint(ax_description(axi.address_width, axi.id_width))
343 self.comb += ax_burst.connect(ax_buffer.sink)
344 ax_burst2beat = AXIBurst2Beat(ax_buffer.source, ax_beat)
345 self.submodules += ax_buffer, ax_burst2beat
346
347 _data = Signal(axi.data_width)
348 _cmd_done = Signal()
349 _last_ar_aw_n = Signal()
350
351 self.submodules.fsm = fsm = FSM(reset_state="IDLE")
352 fsm.act("IDLE",
353 NextValue(_cmd_done, 0),
354 If(axi.ar.valid & axi.aw.valid,
355 # If last access was a read, do a write
356 If(_last_ar_aw_n,
357 axi.aw.connect(ax_burst),
358 NextValue(_last_ar_aw_n, 0),
359 NextState("WRITE")
360 # If last access was a write, do a read
361 ).Else(
362 axi.ar.connect(ax_burst),
363 NextValue(_last_ar_aw_n, 1),
364 NextState("READ"),
365 )
366 ).Elif(axi.ar.valid,
367 axi.ar.connect(ax_burst),
368 NextValue(_last_ar_aw_n, 1),
369 NextState("READ"),
370 ).Elif(axi.aw.valid,
371 axi.aw.connect(ax_burst),
372 NextValue(_last_ar_aw_n, 0),
373 NextState("WRITE")
374 )
375 )
376 fsm.act("READ",
377 # cmd
378 axi_lite.ar.valid.eq(ax_beat.valid & ~_cmd_done),
379 axi_lite.ar.addr.eq(ax_beat.addr),
380 ax_beat.ready.eq(axi_lite.ar.ready & ~_cmd_done),
381 If(ax_beat.valid & ax_beat.last,
382 If(axi_lite.ar.ready,
383 ax_beat.ready.eq(0),
384 NextValue(_cmd_done, 1)
385 )
386 ),
387 # data
388 axi.r.valid.eq(axi_lite.r.valid),
389 axi.r.last.eq(_cmd_done),
390 axi.r.resp.eq(RESP_OKAY),
391 axi.r.id.eq(ax_beat.id),
392 axi.r.data.eq(axi_lite.r.data),
393 axi_lite.r.ready.eq(axi.r.ready),
394 # exit
395 If(axi.r.valid & axi.r.last & axi.r.ready,
396 ax_beat.ready.eq(1),
397 NextState("IDLE")
398 )
399 )
400 # always accept write responses
401 self.comb += axi_lite.b.ready.eq(1)
402 fsm.act("WRITE",
403 # cmd
404 axi_lite.aw.valid.eq(ax_beat.valid & ~_cmd_done),
405 axi_lite.aw.addr.eq(ax_beat.addr),
406 ax_beat.ready.eq(axi_lite.aw.ready & ~_cmd_done),
407 If(ax_beat.valid & ax_beat.last,
408 If(axi_lite.aw.ready,
409 ax_beat.ready.eq(0),
410 NextValue(_cmd_done, 1)
411 )
412 ),
413 # data
414 axi_lite.w.valid.eq(axi.w.valid),
415 axi_lite.w.data.eq(axi.w.data),
416 axi_lite.w.strb.eq(axi.w.strb),
417 axi.w.ready.eq(axi_lite.w.ready),
418 # exit
419 If(axi.w.valid & axi.w.last & axi.w.ready,
420 NextState("WRITE-RESP")
421 )
422 )
423 fsm.act("WRITE-RESP",
424 axi.b.valid.eq(1),
425 axi.b.resp.eq(RESP_OKAY),
426 axi.b.id.eq(ax_beat.id),
427 If(axi.b.ready,
428 ax_beat.ready.eq(1),
429 NextState("IDLE")
430 )
431 )
432
433 # AXI Lite to AXI ----------------------------------------------------------------------------------
434
435 class AXILite2AXI(Module):
436 def __init__(self, axi_lite, axi, write_id=0, read_id=0, prot=0, burst_type="INCR"):
437 assert isinstance(axi_lite, AXILiteInterface)
438 assert isinstance(axi, AXIInterface)
439 assert axi_lite.data_width == axi.data_width
440 assert axi_lite.address_width == axi.address_width
441
442 # n bytes, encoded as log2(n)
443 burst_size = log2_int(axi.data_width // 8)
444 # burst type has no meaning as we use burst length of 1, but AXI slaves may require
445 # certain type of bursts, so it is probably safest to use INCR in general
446 burst_type = {
447 "FIXED": 0b00,
448 "INCR": 0b01,
449 "WRAP": 0b10,
450 }[burst_type]
451
452 self.comb += [
453 axi.aw.valid.eq(axi_lite.aw.valid),
454 axi_lite.aw.ready.eq(axi.aw.ready),
455 axi.aw.addr.eq(axi_lite.aw.addr),
456 axi.aw.burst.eq(burst_type),
457 axi.aw.len.eq(0), # 1 transfer per burst
458 axi.aw.size.eq(burst_size),
459 axi.aw.lock.eq(0), # Normal access
460 axi.aw.prot.eq(prot),
461 axi.aw.cache.eq(0b0011), # Normal Non-cacheable Bufferable
462 axi.aw.qos.eq(0),
463 axi.aw.id.eq(write_id),
464
465 axi.w.valid.eq(axi_lite.w.valid),
466 axi_lite.w.ready.eq(axi.w.ready),
467 axi.w.data.eq(axi_lite.w.data),
468 axi.w.strb.eq(axi_lite.w.strb),
469 axi.w.last.eq(1),
470
471 axi_lite.b.valid.eq(axi.b.valid),
472 axi_lite.b.resp.eq(axi.b.resp),
473 axi.b.ready.eq(axi_lite.b.ready),
474
475 axi.ar.valid.eq(axi_lite.ar.valid),
476 axi_lite.ar.ready.eq(axi.ar.ready),
477 axi.ar.addr.eq(axi_lite.ar.addr),
478 axi.ar.burst.eq(burst_type),
479 axi.ar.len.eq(0),
480 axi.ar.size.eq(burst_size),
481 axi.ar.lock.eq(0),
482 axi.ar.prot.eq(prot),
483 axi.ar.cache.eq(0b0011),
484 axi.ar.qos.eq(0),
485 axi.ar.id.eq(read_id),
486
487 axi_lite.r.valid.eq(axi.r.valid),
488 axi_lite.r.resp.eq(axi.r.resp),
489 axi_lite.r.data.eq(axi.r.data),
490 axi.r.ready.eq(axi_lite.r.ready),
491 ]
492
493 # AXI Lite to Wishbone -----------------------------------------------------------------------------
494
495 class AXILite2Wishbone(Module):
496 def __init__(self, axi_lite, wishbone, base_address=0x00000000):
497 wishbone_adr_shift = log2_int(axi_lite.data_width//8)
498 assert axi_lite.data_width == len(wishbone.dat_r)
499 assert axi_lite.address_width == len(wishbone.adr) + wishbone_adr_shift
500
501 _data = Signal(axi_lite.data_width)
502 _r_addr = Signal(axi_lite.address_width)
503 _w_addr = Signal(axi_lite.address_width)
504 _last_ar_aw_n = Signal()
505 self.comb += _r_addr.eq(axi_lite.ar.addr - base_address)
506 self.comb += _w_addr.eq(axi_lite.aw.addr - base_address)
507
508 self.submodules.fsm = fsm = FSM(reset_state="IDLE")
509 fsm.act("IDLE",
510 If(axi_lite.ar.valid & axi_lite.aw.valid,
511 # If last access was a read, do a write
512 If(_last_ar_aw_n,
513 NextValue(_last_ar_aw_n, 0),
514 NextState("DO-WRITE")
515 # If last access was a write, do a read
516 ).Else(
517 NextValue(_last_ar_aw_n, 1),
518 NextState("DO-READ")
519 )
520 ).Elif(axi_lite.ar.valid,
521 NextValue(_last_ar_aw_n, 1),
522 NextState("DO-READ")
523 ).Elif(axi_lite.aw.valid,
524 NextValue(_last_ar_aw_n, 0),
525 NextState("DO-WRITE")
526 )
527 )
528 fsm.act("DO-READ",
529 wishbone.stb.eq(1),
530 wishbone.cyc.eq(1),
531 wishbone.adr.eq(_r_addr[wishbone_adr_shift:]),
532 wishbone.sel.eq(2**len(wishbone.sel) - 1),
533 If(wishbone.ack,
534 axi_lite.ar.ready.eq(1),
535 NextValue(_data, wishbone.dat_r),
536 NextState("SEND-READ-RESPONSE")
537 )
538 )
539 fsm.act("SEND-READ-RESPONSE",
540 axi_lite.r.valid.eq(1),
541 axi_lite.r.resp.eq(RESP_OKAY),
542 axi_lite.r.data.eq(_data),
543 If(axi_lite.r.ready,
544 NextState("IDLE")
545 )
546 )
547 fsm.act("DO-WRITE",
548 wishbone.stb.eq(axi_lite.w.valid),
549 wishbone.cyc.eq(axi_lite.w.valid),
550 wishbone.we.eq(1),
551 wishbone.adr.eq(_w_addr[wishbone_adr_shift:]),
552 wishbone.sel.eq(axi_lite.w.strb),
553 wishbone.dat_w.eq(axi_lite.w.data),
554 If(wishbone.ack,
555 axi_lite.aw.ready.eq(1),
556 axi_lite.w.ready.eq(1),
557 NextState("SEND-WRITE-RESPONSE")
558 )
559 )
560 fsm.act("SEND-WRITE-RESPONSE",
561 axi_lite.b.valid.eq(1),
562 axi_lite.b.resp.eq(RESP_OKAY),
563 If(axi_lite.b.ready,
564 NextState("IDLE")
565 )
566 )
567
568 # AXI to Wishbone ----------------------------------------------------------------------------------
569
570 class AXI2Wishbone(Module):
571 def __init__(self, axi, wishbone, base_address=0x00000000):
572 axi_lite = AXILiteInterface(axi.data_width, axi.address_width)
573 axi2axi_lite = AXI2AXILite(axi, axi_lite)
574 axi_lite2wishbone = AXILite2Wishbone(axi_lite, wishbone, base_address)
575 self.submodules += axi2axi_lite, axi_lite2wishbone
576
577 # Wishbone to AXILite ------------------------------------------------------------------------------
578
579 class Wishbone2AXILite(Module):
580 def __init__(self, wishbone, axi_lite, base_address=0x00000000):
581 wishbone_adr_shift = log2_int(axi_lite.data_width//8)
582 assert axi_lite.data_width == len(wishbone.dat_r)
583 assert axi_lite.address_width == len(wishbone.adr) + wishbone_adr_shift
584
585 _cmd_done = Signal()
586 _data_done = Signal()
587 _addr = Signal(len(wishbone.adr))
588 self.comb += _addr.eq(wishbone.adr - base_address//4)
589
590 self.submodules.fsm = fsm = FSM(reset_state="IDLE")
591 fsm.act("IDLE",
592 NextValue(_cmd_done, 0),
593 NextValue(_data_done, 0),
594 If(wishbone.stb & wishbone.cyc,
595 If(wishbone.we,
596 NextState("WRITE")
597 ).Else(
598 NextState("READ")
599 )
600 )
601 )
602 fsm.act("WRITE",
603 # cmd
604 axi_lite.aw.valid.eq(~_cmd_done),
605 axi_lite.aw.addr[wishbone_adr_shift:].eq(_addr),
606 If(axi_lite.aw.valid & axi_lite.aw.ready,
607 NextValue(_cmd_done, 1)
608 ),
609 # data
610 axi_lite.w.valid.eq(~_data_done),
611 axi_lite.w.data.eq(wishbone.dat_w),
612 axi_lite.w.strb.eq(wishbone.sel),
613 If(axi_lite.w.valid & axi_lite.w.ready,
614 NextValue(_data_done, 1),
615 ),
616 # resp
617 axi_lite.b.ready.eq(_cmd_done & _data_done),
618 If(axi_lite.b.valid & axi_lite.b.ready,
619 If(axi_lite.b.resp == RESP_OKAY,
620 wishbone.ack.eq(1),
621 NextState("IDLE")
622 ).Else(
623 NextState("ERROR")
624 )
625 )
626 )
627 fsm.act("READ",
628 # cmd
629 axi_lite.ar.valid.eq(~_cmd_done),
630 axi_lite.ar.addr[wishbone_adr_shift:].eq(_addr),
631 If(axi_lite.ar.valid & axi_lite.ar.ready,
632 NextValue(_cmd_done, 1)
633 ),
634 # data & resp
635 axi_lite.r.ready.eq(_cmd_done),
636 If(axi_lite.r.valid & axi_lite.r.ready,
637 If(axi_lite.r.resp == RESP_OKAY,
638 wishbone.dat_r.eq(axi_lite.r.data),
639 wishbone.ack.eq(1),
640 NextState("IDLE"),
641 ).Else(
642 NextState("ERROR")
643 )
644 )
645 )
646 fsm.act("ERROR",
647 wishbone.ack.eq(1),
648 wishbone.err.eq(1),
649 NextState("IDLE")
650 )
651
652 # Wishbone to AXI ----------------------------------------------------------------------------------
653
654 class Wishbone2AXI(Module):
655 def __init__(self, wishbone, axi, base_address=0x00000000):
656 axi_lite = AXILiteInterface(axi.data_width, axi.address_width)
657 wishbone2axi_lite = Wishbone2AXILite(wishbone, axi_lite, base_address)
658 axi_lite2axi = AXILite2AXI(axi_lite, axi)
659 self.submodules += wishbone2axi_lite, axi_lite2axi
660
661 # AXILite to CSR -----------------------------------------------------------------------------------
662
663 def axi_lite_to_simple(axi_lite, port_adr, port_dat_r, port_dat_w=None, port_we=None):
664 """Connection of AXILite to simple bus with 1-cycle latency, such as CSR bus or Memory port"""
665 bus_data_width = axi_lite.data_width
666 adr_shift = log2_int(bus_data_width//8)
667 do_read = Signal()
668 do_write = Signal()
669 last_was_read = Signal()
670
671 comb = []
672 if port_dat_w is not None:
673 comb.append(port_dat_w.eq(axi_lite.w.data))
674 if port_we is not None:
675 if len(port_we) > 1:
676 for i in range(bus_data_width//8):
677 comb.append(port_we[i].eq(axi_lite.w.valid & axi_lite.w.ready & axi_lite.w.strb[i]))
678 else:
679 comb.append(port_we.eq(axi_lite.w.valid & axi_lite.w.ready & (axi_lite.w.strb != 0)))
680
681 fsm = FSM()
682 fsm.act("START-TRANSACTION",
683 # If the last access was a read, do a write, and vice versa
684 If(axi_lite.aw.valid & axi_lite.ar.valid,
685 do_write.eq(last_was_read),
686 do_read.eq(~last_was_read),
687 ).Else(
688 do_write.eq(axi_lite.aw.valid),
689 do_read.eq(axi_lite.ar.valid),
690 ),
691 # Start reading/writing immediately not to waste a cycle
692 If(do_write,
693 port_adr.eq(axi_lite.aw.addr[adr_shift:]),
694 If(axi_lite.w.valid,
695 axi_lite.aw.ready.eq(1),
696 axi_lite.w.ready.eq(1),
697 NextState("SEND-WRITE-RESPONSE")
698 )
699 ).Elif(do_read,
700 port_adr.eq(axi_lite.ar.addr[adr_shift:]),
701 axi_lite.ar.ready.eq(1),
702 NextState("SEND-READ-RESPONSE"),
703 )
704 )
705 fsm.act("SEND-READ-RESPONSE",
706 NextValue(last_was_read, 1),
707 # As long as we have correct address port.dat_r will be valid
708 port_adr.eq(axi_lite.ar.addr[adr_shift:]),
709 axi_lite.r.data.eq(port_dat_r),
710 axi_lite.r.resp.eq(RESP_OKAY),
711 axi_lite.r.valid.eq(1),
712 If(axi_lite.r.ready,
713 NextState("START-TRANSACTION")
714 )
715 )
716 fsm.act("SEND-WRITE-RESPONSE",
717 NextValue(last_was_read, 0),
718 axi_lite.b.valid.eq(1),
719 axi_lite.b.resp.eq(RESP_OKAY),
720 If(axi_lite.b.ready,
721 NextState("START-TRANSACTION")
722 )
723 )
724 return fsm, comb
725
726 class AXILite2CSR(Module):
727 def __init__(self, axi_lite=None, bus_csr=None):
728 if axi_lite is None:
729 axi_lite = AXILiteInterface()
730 if bus_csr is None:
731 bus_csr = csr_bus.Interface()
732
733 self.axi_lite = axi_lite
734 self.csr = bus_csr
735
736 fsm, comb = axi_lite_to_simple(self.axi_lite,
737 port_adr=self.csr.adr, port_dat_r=self.csr.dat_r,
738 port_dat_w=self.csr.dat_w, port_we=self.csr.we)
739 self.submodules.fsm = fsm
740 self.comb += comb
741
742 # AXILite SRAM -------------------------------------------------------------------------------------
743
744 class AXILiteSRAM(Module):
745 def __init__(self, mem_or_size, read_only=None, init=None, bus=None):
746 if bus is None:
747 bus = AXILiteInterface()
748 self.bus = bus
749
750 bus_data_width = len(self.bus.r.data)
751 if isinstance(mem_or_size, Memory):
752 assert(mem_or_size.width <= bus_data_width)
753 self.mem = mem_or_size
754 else:
755 self.mem = Memory(bus_data_width, mem_or_size//(bus_data_width//8), init=init)
756
757 if read_only is None:
758 if hasattr(self.mem, "bus_read_only"):
759 read_only = self.mem.bus_read_only
760 else:
761 read_only = False
762
763 ###
764
765 # Create memory port
766 port = self.mem.get_port(write_capable=not read_only, we_granularity=8,
767 mode=READ_FIRST if read_only else WRITE_FIRST)
768 self.specials += self.mem, port
769
770 # Generate write enable signal
771 if not read_only:
772 self.comb += port.dat_w.eq(self.bus.w.data),
773 self.comb += [port.we[i].eq(self.bus.w.valid & self.bus.w.ready & self.bus.w.strb[i])
774 for i in range(bus_data_width//8)]
775
776 # Transaction logic
777 fsm, comb = axi_lite_to_simple(self.bus,
778 port_adr=port.adr, port_dat_r=port.dat_r,
779 port_dat_w=port.dat_w if not read_only else None,
780 port_we=port.we if not read_only else None)
781 self.submodules.fsm = fsm
782 self.comb += comb
783
784 # AXILite Data Width Converter ---------------------------------------------------------------------
785
786 class _AXILiteDownConverterWrite(Module):
787 def __init__(self, master, slave):
788 assert isinstance(master, AXILiteInterface) and isinstance(slave, AXILiteInterface)
789 dw_from = len(master.w.data)
790 dw_to = len(slave.w.data)
791 ratio = dw_from//dw_to
792 master_align = log2_int(master.data_width//8)
793 slave_align = log2_int(slave.data_width//8)
794
795 skip = Signal()
796 counter = Signal(max=ratio)
797 aw_ready = Signal()
798 w_ready = Signal()
799 resp = Signal.like(master.b.resp)
800 addr_counter = Signal(master_align)
801
802 # # #
803
804 # Slave address counter
805 self.comb += addr_counter[slave_align:].eq(counter)
806
807 # Data path
808 self.comb += [
809 slave.aw.addr.eq(Cat(addr_counter, master.aw.addr[master_align:])),
810 Case(counter, {i: slave.w.data.eq(master.w.data[i*dw_to:]) for i in range(ratio)}),
811 Case(counter, {i: slave.w.strb.eq(master.w.strb[i*dw_to//8:]) for i in range(ratio)}),
812 master.b.resp.eq(resp),
813 ]
814
815 # Control Path
816 fsm = FSM(reset_state="IDLE")
817 fsm = ResetInserter()(fsm)
818 self.submodules.fsm = fsm
819 # Reset the converter state if master breaks a request, we can do that as
820 # aw.valid and w.valid are kept high in CONVERT and RESPOND-SLAVE, and
821 # acknowledged only when moving to RESPOND-MASTER, and then b.valid is 1
822 self.comb += fsm.reset.eq(~((master.aw.valid | master.w.valid) | master.b.valid))
823
824 fsm.act("IDLE",
825 NextValue(counter, 0),
826 NextValue(resp, RESP_OKAY),
827 If(master.aw.valid & master.w.valid,
828 NextState("CONVERT")
829 )
830 )
831 fsm.act("CONVERT",
832 skip.eq(slave.w.strb == 0),
833 slave.aw.valid.eq(~skip & ~aw_ready),
834 slave.w.valid.eq(~skip & ~w_ready),
835 If(slave.aw.ready,
836 NextValue(aw_ready, 1)
837 ),
838 If(slave.w.ready,
839 NextValue(w_ready, 1)
840 ),
841 # When skipping, we just increment the counter
842 If(skip,
843 NextValue(counter, counter + 1),
844 # Corner-case: when the last word is being skipped, we must send the response
845 If(counter == (ratio - 1),
846 master.aw.ready.eq(1),
847 master.w.ready.eq(1),
848 NextState("RESPOND-MASTER")
849 )
850 # Write current word and wait for write response
851 ).Elif((slave.aw.ready | aw_ready) & (slave.w.ready | w_ready),
852 NextState("RESPOND-SLAVE")
853 )
854 )
855 fsm.act("RESPOND-SLAVE",
856 NextValue(aw_ready, 0),
857 NextValue(w_ready, 0),
858 If(slave.b.valid,
859 slave.b.ready.eq(1),
860 # Errors are sticky, so the first one is always sent
861 If((resp == RESP_OKAY) & (slave.b.resp != RESP_OKAY),
862 NextValue(resp, slave.b.resp)
863 ),
864 If(counter == (ratio - 1),
865 master.aw.ready.eq(1),
866 master.w.ready.eq(1),
867 NextState("RESPOND-MASTER")
868 ).Else(
869 NextValue(counter, counter + 1),
870 NextState("CONVERT")
871 )
872 )
873 )
874 fsm.act("RESPOND-MASTER",
875 NextValue(aw_ready, 0),
876 NextValue(w_ready, 0),
877 master.b.valid.eq(1),
878 If(master.b.ready,
879 NextState("IDLE")
880 )
881 )
882
883 class _AXILiteDownConverterRead(Module):
884 def __init__(self, master, slave):
885 assert isinstance(master, AXILiteInterface) and isinstance(slave, AXILiteInterface)
886 dw_from = len(master.r.data)
887 dw_to = len(slave.r.data)
888 ratio = dw_from//dw_to
889 master_align = log2_int(master.data_width//8)
890 slave_align = log2_int(slave.data_width//8)
891
892 skip = Signal()
893 counter = Signal(max=ratio)
894 resp = Signal.like(master.r.resp)
895 addr_counter = Signal(master_align)
896
897 # # #
898
899 # Slave address counter
900 self.comb += addr_counter[slave_align:].eq(counter)
901
902 # Data path
903 # shift the data word
904 r_data = Signal(dw_from, reset_less=True)
905 self.sync += If(slave.r.ready, r_data.eq(master.r.data))
906 self.comb += master.r.data.eq(Cat(r_data[dw_to:], slave.r.data))
907 # address, resp
908 self.comb += [
909 slave.ar.addr.eq(Cat(addr_counter, master.ar.addr[master_align:])),
910 master.r.resp.eq(resp),
911 ]
912
913 # Control Path
914 fsm = FSM(reset_state="IDLE")
915 fsm = ResetInserter()(fsm)
916 self.submodules.fsm = fsm
917 # Reset the converter state if master breaks a request, we can do that as
918 # ar.valid is high in CONVERT and RESPOND-SLAVE, and r.valid in RESPOND-MASTER
919 self.comb += fsm.reset.eq(~(master.ar.valid | master.r.valid))
920
921 fsm.act("IDLE",
922 NextValue(counter, 0),
923 NextValue(resp, RESP_OKAY),
924 If(master.ar.valid,
925 NextState("CONVERT")
926 )
927 )
928 fsm.act("CONVERT",
929 slave.ar.valid.eq(1),
930 If(slave.ar.ready,
931 NextState("RESPOND-SLAVE")
932 )
933 )
934 fsm.act("RESPOND-SLAVE",
935 If(slave.r.valid,
936 # Errors are sticky, so the first one is always sent
937 If((resp == RESP_OKAY) & (slave.r.resp != RESP_OKAY),
938 NextValue(resp, slave.r.resp)
939 ),
940 # On last word acknowledge ar and hold slave.r.valid until we get master.r.ready
941 If(counter == (ratio - 1),
942 master.ar.ready.eq(1),
943 NextState("RESPOND-MASTER")
944 # Acknowledge the response and continue conversion
945 ).Else(
946 slave.r.ready.eq(1),
947 NextValue(counter, counter + 1),
948 NextState("CONVERT")
949 )
950 )
951 )
952 fsm.act("RESPOND-MASTER",
953 master.r.valid.eq(1),
954 If(master.r.ready,
955 slave.r.ready.eq(1),
956 NextState("IDLE")
957 )
958 )
959
960 class AXILiteDownConverter(Module):
961 def __init__(self, master, slave):
962 self.submodules.write = _AXILiteDownConverterWrite(master, slave)
963 self.submodules.read = _AXILiteDownConverterRead(master, slave)
964
965 class AXILiteUpConverter(Module):
966 # TODO: we could try joining multiple master accesses into single slave access
967 # would reuqire checking if address changes and a way to flush on single access
968 def __init__(self, master, slave):
969 assert isinstance(master, AXILiteInterface) and isinstance(slave, AXILiteInterface)
970 dw_from = len(master.r.data)
971 dw_to = len(slave.r.data)
972 ratio = dw_to//dw_from
973 master_align = log2_int(master.data_width//8)
974 slave_align = log2_int(slave.data_width//8)
975
976 wr_word = Signal(log2_int(ratio))
977 rd_word = Signal(log2_int(ratio))
978 wr_word_r = Signal(log2_int(ratio))
979 rd_word_r = Signal(log2_int(ratio))
980
981 # # #
982
983 self.comb += master.connect(slave, omit={"addr", "strb", "data"})
984
985 # Address
986 self.comb += [
987 slave.aw.addr[slave_align:].eq(master.aw.addr[slave_align:]),
988 slave.ar.addr[slave_align:].eq(master.ar.addr[slave_align:]),
989 ]
990
991 # Data path
992 wr_cases, rd_cases = {}, {}
993 for i in range(ratio):
994 strb_from = i * dw_from//8
995 strb_to = (i+1) * dw_from//8
996 data_from = i * dw_from
997 data_to = (i+1) * dw_from
998 wr_cases[i] = [
999 slave.w.strb[strb_from:strb_to].eq(master.w.strb),
1000 slave.w.data[data_from:data_to].eq(master.w.data),
1001 ]
1002 rd_cases[i] = [
1003 master.r.data.eq(slave.r.data[data_from:data_to]),
1004 ]
1005
1006 # Switch current word based on the last valid master address
1007 self.sync += If(master.aw.valid, wr_word_r.eq(wr_word))
1008 self.sync += If(master.ar.valid, rd_word_r.eq(rd_word))
1009 self.comb += [
1010 Case(master.aw.valid, {
1011 0: wr_word.eq(wr_word_r),
1012 1: wr_word.eq(master.aw.addr[master_align:slave_align]),
1013 }),
1014 Case(master.ar.valid, {
1015 0: rd_word.eq(rd_word_r),
1016 1: rd_word.eq(master.ar.addr[master_align:slave_align]),
1017 }),
1018 ]
1019
1020 self.comb += Case(wr_word, wr_cases)
1021 self.comb += Case(rd_word, rd_cases)
1022
1023 class AXILiteConverter(Module):
1024 """AXILite data width converter"""
1025 def __init__(self, master, slave):
1026 self.master = master
1027 self.slave = slave
1028
1029 # # #
1030
1031 dw_from = len(master.r.data)
1032 dw_to = len(slave.r.data)
1033 if dw_from > dw_to:
1034 self.submodules += AXILiteDownConverter(master, slave)
1035 elif dw_from < dw_to:
1036 self.submodules += AXILiteUpConverter(master, slave)
1037 else:
1038 self.comb += master.connect(slave)
1039
1040 # AXILite Timeout ----------------------------------------------------------------------------------
1041
1042 class AXILiteTimeout(Module):
1043 """Protect master against slave timeouts (master _has_ to respond correctly)"""
1044 def __init__(self, master, cycles):
1045 self.error = Signal()
1046 wr_error = Signal()
1047 rd_error = Signal()
1048
1049 # # #
1050
1051 self.comb += self.error.eq(wr_error | rd_error)
1052
1053 wr_timer = WaitTimer(int(cycles))
1054 rd_timer = WaitTimer(int(cycles))
1055 self.submodules += wr_timer, rd_timer
1056
1057 def channel_fsm(timer, wait_cond, error, response):
1058 fsm = FSM(reset_state="WAIT")
1059 fsm.act("WAIT",
1060 timer.wait.eq(wait_cond),
1061 # done is updated in `sync`, so we must make sure that `ready` has not been issued
1062 # by slave during that single cycle, by checking `timer.wait`
1063 If(timer.done & timer.wait,
1064 error.eq(1),
1065 NextState("RESPOND")
1066 )
1067 )
1068 fsm.act("RESPOND", *response)
1069 return fsm
1070
1071 self.submodules.wr_fsm = channel_fsm(
1072 timer = wr_timer,
1073 wait_cond = (master.aw.valid & ~master.aw.ready) | (master.w.valid & ~master.w.ready),
1074 error = wr_error,
1075 response = [
1076 master.aw.ready.eq(master.aw.valid),
1077 master.w.ready.eq(master.w.valid),
1078 master.b.valid.eq(~master.aw.valid & ~master.w.valid),
1079 master.b.resp.eq(RESP_SLVERR),
1080 If(master.b.valid & master.b.ready,
1081 NextState("WAIT")
1082 )
1083 ])
1084
1085 self.submodules.rd_fsm = channel_fsm(
1086 timer = rd_timer,
1087 wait_cond = master.ar.valid & ~master.ar.ready,
1088 error = rd_error,
1089 response = [
1090 master.ar.ready.eq(master.ar.valid),
1091 master.r.valid.eq(~master.ar.valid),
1092 master.r.resp.eq(RESP_SLVERR),
1093 master.r.data.eq(2**len(master.r.data) - 1),
1094 If(master.r.valid & master.r.ready,
1095 NextState("WAIT")
1096 )
1097 ])
1098
1099 # AXILite Interconnect -----------------------------------------------------------------------------
1100
1101 class _AXILiteRequestCounter(Module):
1102 def __init__(self, request, response, max_requests=256):
1103 self.counter = counter = Signal(max=max_requests)
1104 self.full = full = Signal()
1105 self.empty = empty = Signal()
1106 self.stall = stall = Signal()
1107 self.ready = self.empty
1108
1109 self.comb += [
1110 full.eq(counter == max_requests - 1),
1111 empty.eq(counter == 0),
1112 stall.eq(request & full),
1113 ]
1114
1115 self.sync += [
1116 If(request & response,
1117 counter.eq(counter)
1118 ).Elif(request & ~full,
1119 counter.eq(counter + 1)
1120 ).Elif(response & ~empty,
1121 counter.eq(counter - 1)
1122 ),
1123 ]
1124
1125 class AXILiteInterconnectPointToPoint(Module):
1126 def __init__(self, master, slave):
1127 self.comb += master.connect(slave)
1128
1129 class AXILiteArbiter(Module):
1130 """AXI Lite arbiter
1131
1132 Arbitrate between master interfaces and connect one to the target.
1133 New master will not be selected until all requests have been responded to.
1134 Arbitration for write and read channels is done separately.
1135 """
1136 def __init__(self, masters, target):
1137 self.submodules.rr_write = roundrobin.RoundRobin(len(masters), roundrobin.SP_CE)
1138 self.submodules.rr_read = roundrobin.RoundRobin(len(masters), roundrobin.SP_CE)
1139
1140 def get_sig(interface, channel, name):
1141 return getattr(getattr(interface, channel), name)
1142
1143 # mux master->slave signals
1144 for channel, name, direction in target.layout_flat():
1145 rr = self.rr_write if channel in ["aw", "w", "b"] else self.rr_read
1146 if direction == DIR_M_TO_S:
1147 choices = Array(get_sig(m, channel, name) for m in masters)
1148 self.comb += get_sig(target, channel, name).eq(choices[rr.grant])
1149
1150 # connect slave->master signals
1151 for channel, name, direction in target.layout_flat():
1152 rr = self.rr_write if channel in ["aw", "w", "b"] else self.rr_read
1153 if direction == DIR_S_TO_M:
1154 source = get_sig(target, channel, name)
1155 for i, m in enumerate(masters):
1156 dest = get_sig(m, channel, name)
1157 if name == "ready":
1158 self.comb += dest.eq(source & (rr.grant == i))
1159 else:
1160 self.comb += dest.eq(source)
1161
1162 # allow to change rr.grant only after all requests from a master have been responded to
1163 self.submodules.wr_lock = wr_lock = _AXILiteRequestCounter(
1164 request=target.aw.valid & target.aw.ready, response=target.b.valid & target.b.ready)
1165 self.submodules.rd_lock = rd_lock = _AXILiteRequestCounter(
1166 request=target.ar.valid & target.ar.ready, response=target.r.valid & target.r.ready)
1167
1168 # switch to next request only if there are no responses pending
1169 self.comb += [
1170 self.rr_write.ce.eq(~(target.aw.valid | target.w.valid | target.b.valid) & wr_lock.ready),
1171 self.rr_read.ce.eq(~(target.ar.valid | target.r.valid) & rd_lock.ready),
1172 ]
1173
1174 # connect bus requests to round-robin selectors
1175 self.comb += [
1176 self.rr_write.request.eq(Cat(*[m.aw.valid | m.w.valid | m.b.valid for m in masters])),
1177 self.rr_read.request.eq(Cat(*[m.ar.valid | m.r.valid for m in masters])),
1178 ]
1179
1180 class AXILiteDecoder(Module):
1181 _doc_slaves = """
1182 slaves: [(decoder, slave), ...]
1183 List of slaves with address decoders, where `decoder` is a function:
1184 decoder(Signal(address_width - log2(data_width//8))) -> Signal(1)
1185 that returns 1 when the slave is selected and 0 otherwise.
1186 """.strip()
1187
1188 __doc__ = """AXI Lite decoder
1189
1190 Decode master access to particular slave based on its decoder function.
1191
1192 {slaves}
1193 """.format(slaves=_doc_slaves)
1194
1195 def __init__(self, master, slaves, register=False):
1196 # TODO: unused register argument
1197 addr_shift = log2_int(master.data_width//8)
1198
1199 channels = {
1200 "write": {"aw", "w", "b"},
1201 "read": {"ar", "r"},
1202 }
1203 # reverse mapping: directions[channel] -> "write"/"read"
1204 directions = {ch: d for d, chs in channels.items() for ch in chs}
1205
1206 def new_slave_sel():
1207 return {"write": Signal(len(slaves)), "read": Signal(len(slaves))}
1208
1209 slave_sel_dec = new_slave_sel()
1210 slave_sel_reg = new_slave_sel()
1211 slave_sel = new_slave_sel()
1212
1213 # we need to hold the slave selected until all responses come back
1214 # TODO: we could reuse arbiter counters
1215 locks = {
1216 "write": _AXILiteRequestCounter(
1217 request=master.aw.valid & master.aw.ready,
1218 response=master.b.valid & master.b.ready),
1219 "read": _AXILiteRequestCounter(
1220 request=master.ar.valid & master.ar.ready,
1221 response=master.r.valid & master.r.ready),
1222 }
1223 self.submodules += locks.values()
1224
1225 def get_sig(interface, channel, name):
1226 return getattr(getattr(interface, channel), name)
1227
1228 # # #
1229
1230 # decode slave addresses
1231 for i, (decoder, bus) in enumerate(slaves):
1232 self.comb += [
1233 slave_sel_dec["write"][i].eq(decoder(master.aw.addr[addr_shift:])),
1234 slave_sel_dec["read"][i].eq(decoder(master.ar.addr[addr_shift:])),
1235 ]
1236
1237 # change the current selection only when we've got all responses
1238 for channel in locks.keys():
1239 self.sync += If(locks[channel].ready, slave_sel_reg[channel].eq(slave_sel_dec[channel]))
1240 # we have to cut the delaying select
1241 for ch, final in slave_sel.items():
1242 self.comb += If(locks[ch].ready,
1243 final.eq(slave_sel_dec[ch])
1244 ).Else(
1245 final.eq(slave_sel_reg[ch])
1246 )
1247
1248 # connect master->slaves signals except valid/ready
1249 for i, (_, slave) in enumerate(slaves):
1250 for channel, name, direction in master.layout_flat():
1251 if direction == DIR_M_TO_S:
1252 src = get_sig(master, channel, name)
1253 dst = get_sig(slave, channel, name)
1254 # mask master control signals depending on slave selection
1255 if name in ["valid", "ready"]:
1256 src = src & slave_sel[directions[channel]][i]
1257 self.comb += dst.eq(src)
1258
1259 # connect slave->master signals masking not selected slaves
1260 for channel, name, direction in master.layout_flat():
1261 if direction == DIR_S_TO_M:
1262 dst = get_sig(master, channel, name)
1263 masked = []
1264 for i, (_, slave) in enumerate(slaves):
1265 src = get_sig(slave, channel, name)
1266 # mask depending on channel
1267 mask = Replicate(slave_sel[directions[channel]][i], len(dst))
1268 masked.append(src & mask)
1269 self.comb += dst.eq(reduce(or_, masked))
1270
1271 class AXILiteInterconnectShared(Module):
1272 __doc__ = """AXI Lite shared interconnect
1273
1274 {slaves}
1275 """.format(slaves=AXILiteDecoder._doc_slaves)
1276
1277 def __init__(self, masters, slaves, register=False, timeout_cycles=1e6):
1278 # TODO: data width
1279 shared = AXILiteInterface()
1280 self.submodules.arbiter = AXILiteArbiter(masters, shared)
1281 self.submodules.decoder = AXILiteDecoder(shared, slaves)
1282 if timeout_cycles is not None:
1283 self.submodules.timeout = AXILiteTimeout(shared, timeout_cycles)
1284
1285 class AXILiteCrossbar(Module):
1286 __doc__ = """AXI Lite crossbar
1287
1288 MxN crossbar for M masters and N slaves.
1289
1290 {slaves}
1291 """.format(slaves=AXILiteDecoder._doc_slaves)
1292
1293 def __init__(self, masters, slaves, register=False, timeout_cycles=1e6):
1294 matches, busses = zip(*slaves)
1295 access_m_s = [[AXILiteInterface() for j in slaves] for i in masters] # a[master][slave]
1296 access_s_m = list(zip(*access_m_s)) # a[slave][master]
1297 # decode each master into its access row
1298 for slaves, master in zip(access_m_s, masters):
1299 slaves = list(zip(matches, slaves))
1300 self.submodules += AXILiteDecoder(master, slaves, register)
1301 # arbitrate each access column onto its slave
1302 for masters, bus in zip(access_s_m, busses):
1303 self.submodules += AXILiteArbiter(masters, bus)