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