958061a9bbee575280e12e9c9845285a6affbde9
[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 # AXILite to CSR -----------------------------------------------------------------------------------
653
654 def axi_lite_to_simple(axi_lite, port_adr, port_dat_r, port_dat_w=None, port_we=None):
655 """Connection of AXILite to simple bus with 1-cycle latency, such as CSR bus or Memory port"""
656 bus_data_width = axi_lite.data_width
657 adr_shift = log2_int(bus_data_width//8)
658 do_read = Signal()
659 do_write = Signal()
660 last_was_read = Signal()
661
662 comb = []
663 if port_dat_w is not None:
664 comb.append(port_dat_w.eq(axi_lite.w.data))
665 if port_we is not None:
666 if len(port_we) > 1:
667 for i in range(bus_data_width//8):
668 comb.append(port_we[i].eq(axi_lite.w.valid & axi_lite.w.ready & axi_lite.w.strb[i]))
669 else:
670 comb.append(port_we.eq(axi_lite.w.valid & axi_lite.w.ready & (axi_lite.w.strb != 0)))
671
672 fsm = FSM()
673 fsm.act("START-TRANSACTION",
674 # If the last access was a read, do a write, and vice versa
675 If(axi_lite.aw.valid & axi_lite.ar.valid,
676 do_write.eq(last_was_read),
677 do_read.eq(~last_was_read),
678 ).Else(
679 do_write.eq(axi_lite.aw.valid),
680 do_read.eq(axi_lite.ar.valid),
681 ),
682 # Start reading/writing immediately not to waste a cycle
683 If(do_write,
684 port_adr.eq(axi_lite.aw.addr[adr_shift:]),
685 If(axi_lite.w.valid,
686 axi_lite.aw.ready.eq(1),
687 axi_lite.w.ready.eq(1),
688 NextState("SEND-WRITE-RESPONSE")
689 )
690 ).Elif(do_read,
691 port_adr.eq(axi_lite.ar.addr[adr_shift:]),
692 axi_lite.ar.ready.eq(1),
693 NextState("SEND-READ-RESPONSE"),
694 )
695 )
696 fsm.act("SEND-READ-RESPONSE",
697 NextValue(last_was_read, 1),
698 # As long as we have correct address port.dat_r will be valid
699 port_adr.eq(axi_lite.ar.addr[adr_shift:]),
700 axi_lite.r.data.eq(port_dat_r),
701 axi_lite.r.resp.eq(RESP_OKAY),
702 axi_lite.r.valid.eq(1),
703 If(axi_lite.r.ready,
704 NextState("START-TRANSACTION")
705 )
706 )
707 fsm.act("SEND-WRITE-RESPONSE",
708 NextValue(last_was_read, 0),
709 axi_lite.b.valid.eq(1),
710 axi_lite.b.resp.eq(RESP_OKAY),
711 If(axi_lite.b.ready,
712 NextState("START-TRANSACTION")
713 )
714 )
715 return fsm, comb
716
717 class AXILite2CSR(Module):
718 def __init__(self, axi_lite=None, bus_csr=None):
719 if axi_lite is None:
720 axi_lite = AXILiteInterface()
721 if bus_csr is None:
722 bus_csr = csr_bus.Interface()
723
724 self.axi_lite = axi_lite
725 self.csr = bus_csr
726
727 fsm, comb = axi_lite_to_simple(self.axi_lite,
728 port_adr=self.csr.adr, port_dat_r=self.csr.dat_r,
729 port_dat_w=self.csr.dat_w, port_we=self.csr.we)
730 self.submodules.fsm = fsm
731 self.comb += comb
732
733 # AXILite SRAM -------------------------------------------------------------------------------------
734
735 class AXILiteSRAM(Module):
736 def __init__(self, mem_or_size, read_only=None, init=None, bus=None):
737 if bus is None:
738 bus = AXILiteInterface()
739 self.bus = bus
740
741 bus_data_width = len(self.bus.r.data)
742 if isinstance(mem_or_size, Memory):
743 assert(mem_or_size.width <= bus_data_width)
744 self.mem = mem_or_size
745 else:
746 self.mem = Memory(bus_data_width, mem_or_size//(bus_data_width//8), init=init)
747
748 if read_only is None:
749 if hasattr(self.mem, "bus_read_only"):
750 read_only = self.mem.bus_read_only
751 else:
752 read_only = False
753
754 ###
755
756 # Create memory port
757 port = self.mem.get_port(write_capable=not read_only, we_granularity=8,
758 mode=READ_FIRST if read_only else WRITE_FIRST)
759 self.specials += self.mem, port
760
761 # Generate write enable signal
762 if not read_only:
763 self.comb += port.dat_w.eq(self.bus.w.data),
764 self.comb += [port.we[i].eq(self.bus.w.valid & self.bus.w.ready & self.bus.w.strb[i])
765 for i in range(bus_data_width//8)]
766
767 # Transaction logic
768 fsm, comb = axi_lite_to_simple(self.bus,
769 port_adr=port.adr, port_dat_r=port.dat_r,
770 port_dat_w=port.dat_w if not read_only else None,
771 port_we=port.we if not read_only else None)
772 self.submodules.fsm = fsm
773 self.comb += comb
774
775 # AXILite Data Width Converter ---------------------------------------------------------------------
776
777 class _AXILiteDownConverterWrite(Module):
778 def __init__(self, master, slave):
779 assert isinstance(master, AXILiteInterface) and isinstance(slave, AXILiteInterface)
780 dw_from = len(master.w.data)
781 dw_to = len(slave.w.data)
782 ratio = dw_from//dw_to
783 master_align = log2_int(master.data_width//8)
784 slave_align = log2_int(slave.data_width//8)
785
786 skip = Signal()
787 counter = Signal(max=ratio)
788 aw_ready = Signal()
789 w_ready = Signal()
790 resp = Signal.like(master.b.resp)
791 addr_counter = Signal(master_align)
792
793 # # #
794
795 # Slave address counter
796 self.comb += addr_counter[slave_align:].eq(counter)
797
798 # Data path
799 self.comb += [
800 slave.aw.addr.eq(Cat(addr_counter, master.aw.addr[master_align:])),
801 Case(counter, {i: slave.w.data.eq(master.w.data[i*dw_to:]) for i in range(ratio)}),
802 Case(counter, {i: slave.w.strb.eq(master.w.strb[i*dw_to//8:]) for i in range(ratio)}),
803 master.b.resp.eq(resp),
804 ]
805
806 # Control Path
807 fsm = FSM(reset_state="IDLE")
808 fsm = ResetInserter()(fsm)
809 self.submodules.fsm = fsm
810 # Reset the converter state if master breaks a request, we can do that as
811 # aw.valid and w.valid are kept high in CONVERT and RESPOND-SLAVE, and
812 # acknowledged only when moving to RESPOND-MASTER, and then b.valid is 1
813 self.comb += fsm.reset.eq(~((master.aw.valid | master.w.valid) | master.b.valid))
814
815 fsm.act("IDLE",
816 NextValue(counter, 0),
817 NextValue(resp, RESP_OKAY),
818 If(master.aw.valid & master.w.valid,
819 NextState("CONVERT")
820 )
821 )
822 fsm.act("CONVERT",
823 skip.eq(slave.w.strb == 0),
824 slave.aw.valid.eq(~skip & ~aw_ready),
825 slave.w.valid.eq(~skip & ~w_ready),
826 If(slave.aw.ready,
827 NextValue(aw_ready, 1)
828 ),
829 If(slave.w.ready,
830 NextValue(w_ready, 1)
831 ),
832 # When skipping, we just increment the counter
833 If(skip,
834 NextValue(counter, counter + 1),
835 # Corner-case: when the last word is being skipped, we must send the response
836 If(counter == (ratio - 1),
837 master.aw.ready.eq(1),
838 master.w.ready.eq(1),
839 NextState("RESPOND-MASTER")
840 )
841 # Write current word and wait for write response
842 ).Elif((slave.aw.ready | aw_ready) & (slave.w.ready | w_ready),
843 NextState("RESPOND-SLAVE")
844 )
845 )
846 fsm.act("RESPOND-SLAVE",
847 NextValue(aw_ready, 0),
848 NextValue(w_ready, 0),
849 If(slave.b.valid,
850 slave.b.ready.eq(1),
851 # Errors are sticky, so the first one is always sent
852 If((resp == RESP_OKAY) & (slave.b.resp != RESP_OKAY),
853 NextValue(resp, slave.b.resp)
854 ),
855 If(counter == (ratio - 1),
856 master.aw.ready.eq(1),
857 master.w.ready.eq(1),
858 NextState("RESPOND-MASTER")
859 ).Else(
860 NextValue(counter, counter + 1),
861 NextState("CONVERT")
862 )
863 )
864 )
865 fsm.act("RESPOND-MASTER",
866 NextValue(aw_ready, 0),
867 NextValue(w_ready, 0),
868 master.b.valid.eq(1),
869 If(master.b.ready,
870 NextState("IDLE")
871 )
872 )
873
874 class _AXILiteDownConverterRead(Module):
875 def __init__(self, master, slave):
876 assert isinstance(master, AXILiteInterface) and isinstance(slave, AXILiteInterface)
877 dw_from = len(master.r.data)
878 dw_to = len(slave.r.data)
879 ratio = dw_from//dw_to
880 master_align = log2_int(master.data_width//8)
881 slave_align = log2_int(slave.data_width//8)
882
883 skip = Signal()
884 counter = Signal(max=ratio)
885 resp = Signal.like(master.r.resp)
886 addr_counter = Signal(master_align)
887
888 # # #
889
890 # Slave address counter
891 self.comb += addr_counter[slave_align:].eq(counter)
892
893 # Data path
894 # shift the data word
895 r_data = Signal(dw_from, reset_less=True)
896 self.sync += If(slave.r.ready, r_data.eq(master.r.data))
897 self.comb += master.r.data.eq(Cat(r_data[dw_to:], slave.r.data))
898 # address, resp
899 self.comb += [
900 slave.ar.addr.eq(Cat(addr_counter, master.ar.addr[master_align:])),
901 master.r.resp.eq(resp),
902 ]
903
904 # Control Path
905 fsm = FSM(reset_state="IDLE")
906 fsm = ResetInserter()(fsm)
907 self.submodules.fsm = fsm
908 # Reset the converter state if master breaks a request, we can do that as
909 # ar.valid is high in CONVERT and RESPOND-SLAVE, and r.valid in RESPOND-MASTER
910 self.comb += fsm.reset.eq(~(master.ar.valid | master.r.valid))
911
912 fsm.act("IDLE",
913 NextValue(counter, 0),
914 NextValue(resp, RESP_OKAY),
915 If(master.ar.valid,
916 NextState("CONVERT")
917 )
918 )
919 fsm.act("CONVERT",
920 slave.ar.valid.eq(1),
921 If(slave.ar.ready,
922 NextState("RESPOND-SLAVE")
923 )
924 )
925 fsm.act("RESPOND-SLAVE",
926 If(slave.r.valid,
927 # Errors are sticky, so the first one is always sent
928 If((resp == RESP_OKAY) & (slave.r.resp != RESP_OKAY),
929 NextValue(resp, slave.r.resp)
930 ),
931 # On last word acknowledge ar and hold slave.r.valid until we get master.r.ready
932 If(counter == (ratio - 1),
933 master.ar.ready.eq(1),
934 NextState("RESPOND-MASTER")
935 # Acknowledge the response and continue conversion
936 ).Else(
937 slave.r.ready.eq(1),
938 NextValue(counter, counter + 1),
939 NextState("CONVERT")
940 )
941 )
942 )
943 fsm.act("RESPOND-MASTER",
944 master.r.valid.eq(1),
945 If(master.r.ready,
946 slave.r.ready.eq(1),
947 NextState("IDLE")
948 )
949 )
950
951 class AXILiteDownConverter(Module):
952 def __init__(self, master, slave):
953 self.submodules.write = _AXILiteDownConverterWrite(master, slave)
954 self.submodules.read = _AXILiteDownConverterRead(master, slave)
955
956 class AXILiteUpConverter(Module):
957 # TODO: we could try joining multiple master accesses into single slave access
958 # would reuqire checking if address changes and a way to flush on single access
959 def __init__(self, master, slave):
960 assert isinstance(master, AXILiteInterface) and isinstance(slave, AXILiteInterface)
961 dw_from = len(master.r.data)
962 dw_to = len(slave.r.data)
963 ratio = dw_to//dw_from
964 master_align = log2_int(master.data_width//8)
965 slave_align = log2_int(slave.data_width//8)
966
967 wr_word = Signal(log2_int(ratio))
968 rd_word = Signal(log2_int(ratio))
969 wr_word_r = Signal(log2_int(ratio))
970 rd_word_r = Signal(log2_int(ratio))
971
972 # # #
973
974 self.comb += master.connect(slave, omit={"addr", "strb", "data"})
975
976 # Address
977 self.comb += [
978 slave.aw.addr[slave_align:].eq(master.aw.addr[slave_align:]),
979 slave.ar.addr[slave_align:].eq(master.ar.addr[slave_align:]),
980 ]
981
982 # Data path
983 wr_cases, rd_cases = {}, {}
984 for i in range(ratio):
985 strb_from = i * dw_from//8
986 strb_to = (i+1) * dw_from//8
987 data_from = i * dw_from
988 data_to = (i+1) * dw_from
989 wr_cases[i] = [
990 slave.w.strb[strb_from:strb_to].eq(master.w.strb),
991 slave.w.data[data_from:data_to].eq(master.w.data),
992 ]
993 rd_cases[i] = [
994 master.r.data.eq(slave.r.data[data_from:data_to]),
995 ]
996
997 # Switch current word based on the last valid master address
998 self.sync += If(master.aw.valid, wr_word_r.eq(wr_word))
999 self.sync += If(master.ar.valid, rd_word_r.eq(rd_word))
1000 self.comb += [
1001 Case(master.aw.valid, {
1002 0: wr_word.eq(wr_word_r),
1003 1: wr_word.eq(master.aw.addr[master_align:slave_align]),
1004 }),
1005 Case(master.ar.valid, {
1006 0: rd_word.eq(rd_word_r),
1007 1: rd_word.eq(master.ar.addr[master_align:slave_align]),
1008 }),
1009 ]
1010
1011 self.comb += Case(wr_word, wr_cases)
1012 self.comb += Case(rd_word, rd_cases)
1013
1014 class AXILiteConverter(Module):
1015 """AXILite data width converter"""
1016 def __init__(self, master, slave):
1017 self.master = master
1018 self.slave = slave
1019
1020 # # #
1021
1022 dw_from = len(master.r.data)
1023 dw_to = len(slave.r.data)
1024 if dw_from > dw_to:
1025 self.submodules += AXILiteDownConverter(master, slave)
1026 elif dw_from < dw_to:
1027 self.submodules += AXILiteUpConverter(master, slave)
1028 else:
1029 self.comb += master.connect(slave)
1030
1031 # AXILite Timeout ----------------------------------------------------------------------------------
1032
1033 class AXILiteTimeout(Module):
1034 """Protect master against slave timeouts (master _has_ to respond correctly)"""
1035 def __init__(self, master, cycles):
1036 self.error = Signal()
1037 wr_error = Signal()
1038 rd_error = Signal()
1039
1040 # # #
1041
1042 self.comb += self.error.eq(wr_error | rd_error)
1043
1044 wr_timer = WaitTimer(int(cycles))
1045 rd_timer = WaitTimer(int(cycles))
1046 self.submodules += wr_timer, rd_timer
1047
1048 def channel_fsm(timer, wait_cond, error, response):
1049 fsm = FSM(reset_state="WAIT")
1050 fsm.act("WAIT",
1051 timer.wait.eq(wait_cond),
1052 # done is updated in `sync`, so we must make sure that `ready` has not been issued
1053 # by slave during that single cycle, by checking `timer.wait`
1054 If(timer.done & timer.wait,
1055 error.eq(1),
1056 NextState("RESPOND")
1057 )
1058 )
1059 fsm.act("RESPOND", *response)
1060 return fsm
1061
1062 self.submodules.wr_fsm = channel_fsm(
1063 timer = wr_timer,
1064 wait_cond = (master.aw.valid & ~master.aw.ready) | (master.w.valid & ~master.w.ready),
1065 error = wr_error,
1066 response = [
1067 master.aw.ready.eq(master.aw.valid),
1068 master.w.ready.eq(master.w.valid),
1069 master.b.valid.eq(~master.aw.valid & ~master.w.valid),
1070 master.b.resp.eq(RESP_SLVERR),
1071 If(master.b.valid & master.b.ready,
1072 NextState("WAIT")
1073 )
1074 ])
1075
1076 self.submodules.rd_fsm = channel_fsm(
1077 timer = rd_timer,
1078 wait_cond = master.ar.valid & ~master.ar.ready,
1079 error = rd_error,
1080 response = [
1081 master.ar.ready.eq(master.ar.valid),
1082 master.r.valid.eq(~master.ar.valid),
1083 master.r.resp.eq(RESP_SLVERR),
1084 master.r.data.eq(2**len(master.r.data) - 1),
1085 If(master.r.valid & master.r.ready,
1086 NextState("WAIT")
1087 )
1088 ])
1089
1090 # AXILite Interconnect -----------------------------------------------------------------------------
1091
1092 class _AXILiteRequestCounter(Module):
1093 def __init__(self, request, response, max_requests=256):
1094 self.counter = counter = Signal(max=max_requests)
1095 self.full = full = Signal()
1096 self.empty = empty = Signal()
1097 self.stall = stall = Signal()
1098 self.ready = self.empty
1099
1100 self.comb += [
1101 full.eq(counter == max_requests - 1),
1102 empty.eq(counter == 0),
1103 stall.eq(request & full),
1104 ]
1105
1106 self.sync += [
1107 If(request & response,
1108 counter.eq(counter)
1109 ).Elif(request & ~full,
1110 counter.eq(counter + 1)
1111 ).Elif(response & ~empty,
1112 counter.eq(counter - 1)
1113 ),
1114 ]
1115
1116 class AXILiteInterconnectPointToPoint(Module):
1117 def __init__(self, master, slave):
1118 self.comb += master.connect(slave)
1119
1120 class AXILiteArbiter(Module):
1121 """AXI Lite arbiter
1122
1123 Arbitrate between master interfaces and connect one to the target.
1124 New master will not be selected until all requests have been responded to.
1125 Arbitration for write and read channels is done separately.
1126 """
1127 def __init__(self, masters, target):
1128 self.submodules.rr_write = roundrobin.RoundRobin(len(masters), roundrobin.SP_CE)
1129 self.submodules.rr_read = roundrobin.RoundRobin(len(masters), roundrobin.SP_CE)
1130
1131 def get_sig(interface, channel, name):
1132 return getattr(getattr(interface, channel), name)
1133
1134 # mux master->slave signals
1135 for channel, name, direction in target.layout_flat():
1136 rr = self.rr_write if channel in ["aw", "w", "b"] else self.rr_read
1137 if direction == DIR_M_TO_S:
1138 choices = Array(get_sig(m, channel, name) for m in masters)
1139 self.comb += get_sig(target, channel, name).eq(choices[rr.grant])
1140
1141 # connect slave->master signals
1142 for channel, name, direction in target.layout_flat():
1143 rr = self.rr_write if channel in ["aw", "w", "b"] else self.rr_read
1144 if direction == DIR_S_TO_M:
1145 source = get_sig(target, channel, name)
1146 for i, m in enumerate(masters):
1147 dest = get_sig(m, channel, name)
1148 if name == "ready":
1149 self.comb += dest.eq(source & (rr.grant == i))
1150 else:
1151 self.comb += dest.eq(source)
1152
1153 # allow to change rr.grant only after all requests from a master have been responded to
1154 self.submodules.wr_lock = wr_lock = _AXILiteRequestCounter(
1155 request=target.aw.valid & target.aw.ready, response=target.b.valid & target.b.ready)
1156 self.submodules.rd_lock = rd_lock = _AXILiteRequestCounter(
1157 request=target.ar.valid & target.ar.ready, response=target.r.valid & target.r.ready)
1158
1159 # switch to next request only if there are no responses pending
1160 self.comb += [
1161 self.rr_write.ce.eq(~(target.aw.valid | target.w.valid | target.b.valid) & wr_lock.ready),
1162 self.rr_read.ce.eq(~(target.ar.valid | target.r.valid) & rd_lock.ready),
1163 ]
1164
1165 # connect bus requests to round-robin selectors
1166 self.comb += [
1167 self.rr_write.request.eq(Cat(*[m.aw.valid | m.w.valid | m.b.valid for m in masters])),
1168 self.rr_read.request.eq(Cat(*[m.ar.valid | m.r.valid for m in masters])),
1169 ]
1170
1171 class AXILiteDecoder(Module):
1172 _doc_slaves = """
1173 slaves: [(decoder, slave), ...]
1174 List of slaves with address decoders, where `decoder` is a function:
1175 decoder(Signal(address_width - log2(data_width//8))) -> Signal(1)
1176 that returns 1 when the slave is selected and 0 otherwise.
1177 """.strip()
1178
1179 __doc__ = """AXI Lite decoder
1180
1181 Decode master access to particular slave based on its decoder function.
1182
1183 {slaves}
1184 """.format(slaves=_doc_slaves)
1185
1186 def __init__(self, master, slaves, register=False):
1187 # TODO: unused register argument
1188 addr_shift = log2_int(master.data_width//8)
1189
1190 channels = {
1191 "write": {"aw", "w", "b"},
1192 "read": {"ar", "r"},
1193 }
1194 # reverse mapping: directions[channel] -> "write"/"read"
1195 directions = {ch: d for d, chs in channels.items() for ch in chs}
1196
1197 def new_slave_sel():
1198 return {"write": Signal(len(slaves)), "read": Signal(len(slaves))}
1199
1200 slave_sel_dec = new_slave_sel()
1201 slave_sel_reg = new_slave_sel()
1202 slave_sel = new_slave_sel()
1203
1204 # we need to hold the slave selected until all responses come back
1205 # TODO: we could reuse arbiter counters
1206 locks = {
1207 "write": _AXILiteRequestCounter(
1208 request=master.aw.valid & master.aw.ready,
1209 response=master.b.valid & master.b.ready),
1210 "read": _AXILiteRequestCounter(
1211 request=master.ar.valid & master.ar.ready,
1212 response=master.r.valid & master.r.ready),
1213 }
1214 self.submodules += locks.values()
1215
1216 def get_sig(interface, channel, name):
1217 return getattr(getattr(interface, channel), name)
1218
1219 # # #
1220
1221 # decode slave addresses
1222 for i, (decoder, bus) in enumerate(slaves):
1223 self.comb += [
1224 slave_sel_dec["write"][i].eq(decoder(master.aw.addr[addr_shift:])),
1225 slave_sel_dec["read"][i].eq(decoder(master.ar.addr[addr_shift:])),
1226 ]
1227
1228 # change the current selection only when we've got all responses
1229 for channel in locks.keys():
1230 self.sync += If(locks[channel].ready, slave_sel_reg[channel].eq(slave_sel_dec[channel]))
1231 # we have to cut the delaying select
1232 for ch, final in slave_sel.items():
1233 self.comb += If(locks[ch].ready,
1234 final.eq(slave_sel_dec[ch])
1235 ).Else(
1236 final.eq(slave_sel_reg[ch])
1237 )
1238
1239 # connect master->slaves signals except valid/ready
1240 for i, (_, slave) in enumerate(slaves):
1241 for channel, name, direction in master.layout_flat():
1242 if direction == DIR_M_TO_S:
1243 src = get_sig(master, channel, name)
1244 dst = get_sig(slave, channel, name)
1245 # mask master control signals depending on slave selection
1246 if name in ["valid", "ready"]:
1247 src = src & slave_sel[directions[channel]][i]
1248 self.comb += dst.eq(src)
1249
1250 # connect slave->master signals masking not selected slaves
1251 for channel, name, direction in master.layout_flat():
1252 if direction == DIR_S_TO_M:
1253 dst = get_sig(master, channel, name)
1254 masked = []
1255 for i, (_, slave) in enumerate(slaves):
1256 src = get_sig(slave, channel, name)
1257 # mask depending on channel
1258 mask = Replicate(slave_sel[directions[channel]][i], len(dst))
1259 masked.append(src & mask)
1260 self.comb += dst.eq(reduce(or_, masked))
1261
1262 class AXILiteInterconnectShared(Module):
1263 __doc__ = """AXI Lite shared interconnect
1264
1265 {slaves}
1266 """.format(slaves=AXILiteDecoder._doc_slaves)
1267
1268 def __init__(self, masters, slaves, register=False, timeout_cycles=1e6):
1269 # TODO: data width
1270 shared = AXILiteInterface()
1271 self.submodules.arbiter = AXILiteArbiter(masters, shared)
1272 self.submodules.decoder = AXILiteDecoder(shared, slaves)
1273 if timeout_cycles is not None:
1274 self.submodules.timeout = AXILiteTimeout(shared, timeout_cycles)
1275
1276 class AXILiteCrossbar(Module):
1277 __doc__ = """AXI Lite crossbar
1278
1279 MxN crossbar for M masters and N slaves.
1280
1281 {slaves}
1282 """.format(slaves=AXILiteDecoder._doc_slaves)
1283
1284 def __init__(self, masters, slaves, register=False, timeout_cycles=1e6):
1285 matches, busses = zip(*slaves)
1286 access_m_s = [[AXILiteInterface() for j in slaves] for i in masters] # a[master][slave]
1287 access_s_m = list(zip(*access_m_s)) # a[slave][master]
1288 # decode each master into its access row
1289 for slaves, master in zip(access_m_s, masters):
1290 slaves = list(zip(matches, slaves))
1291 self.submodules += AXILiteDecoder(master, slaves, register)
1292 # arbitrate each access column onto its slave
1293 for masters, bus in zip(access_s_m, busses):
1294 self.submodules += AXILiteArbiter(masters, bus)