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>
5 """AXI4 Full/Lite support for LiteX"""
8 from migen
.genlib
import roundrobin
9 from migen
.genlib
.misc
import split
, displacer
, chooser
, WaitTimer
11 from litex
.soc
.interconnect
import stream
12 from litex
.build
.generic_platform
import *
14 from litex
.soc
.interconnect
import csr_bus
16 # AXI Definition -----------------------------------------------------------------------------------
28 def ax_description(address_width
, id_width
):
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)
40 # * present for interconnect with others cores but not used by LiteX.
42 def w_description(data_width
, id_width
):
45 ("strb", data_width
//8),
49 def b_description(id_width
):
55 def r_description(data_width
, id_width
):
62 def _connect_axi(master
, slave
):
71 for channel
, mode
in channel_modes
.items():
73 m
, s
= getattr(master
, channel
), getattr(slave
, channel
)
75 s
, m
= getattr(master
, channel
), getattr(slave
, channel
)
76 r
.extend(m
.connect(s
))
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
]
85 for ch
in ["aw", "w", "b", "ar", "r"]:
86 channel
= getattr(axi
, ch
)
87 for group
in channel
.layout
:
89 name
, _
, direction
= group
90 yield ch
, name
, get_dir(ch
, direction
)
93 for subgroup
in subgroups
:
94 name
, _
, direction
= subgroup
95 yield ch
, name
, get_dir(ch
, direction
)
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
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
))
110 def connect(self
, slave
):
111 return _connect_axi(self
, slave
)
113 def layout_flat(self
):
114 return list(_axi_layout_flat(self
))
116 # AXI Lite Definition ------------------------------------------------------------------------------
118 def ax_lite_description(address_width
):
119 return [("addr", address_width
)]
121 def w_lite_description(data_width
):
123 ("data", data_width
),
124 ("strb", data_width
//8)
127 def b_lite_description():
130 def r_lite_description(data_width
):
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
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
)
148 def get_ios(self
, bus_name
="wb"):
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
)]
158 def connect_to_pads(self
, pads
, mode
="master"):
159 assert mode
in ["slave", "master"]
161 def swap_mode(mode
): return "master" if mode
== "slave" else "slave"
165 "b" : swap_mode(mode
),
167 "r" : swap_mode(mode
),
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
)
174 r
.append(pad
.eq(sig
))
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
)
181 r
.append(sig
.eq(pad
))
183 r
.append(pad
.eq(sig
))
186 def connect(self
, slave
):
187 return _connect_axi(self
, slave
)
189 def layout_flat(self
):
190 return list(_axi_layout_flat(self
))
192 def write(self
, addr
, data
, strb
=None):
194 strb
= 2**len(self
.w
.strb
) - 1
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
)
202 while not (yield self
.aw
.ready
):
204 yield self
.aw
.valid
.eq(0)
205 yield self
.aw
.addr
.eq(0)
206 while not (yield self
.w
.ready
):
208 yield self
.w
.valid
.eq(0)
209 yield self
.w
.strb
.eq(0)
211 yield self
.b
.ready
.eq(1)
212 while not (yield self
.b
.valid
):
214 resp
= (yield self
.b
.resp
)
215 yield self
.b
.ready
.eq(0)
218 def read(self
, addr
):
220 yield self
.ar
.valid
.eq(1)
221 yield self
.ar
.addr
.eq(addr
)
223 while not (yield self
.ar
.ready
):
225 yield self
.ar
.valid
.eq(0)
227 yield self
.r
.ready
.eq(1)
228 while not (yield self
.r
.valid
):
230 data
= (yield self
.r
.data
)
231 resp
= (yield self
.r
.resp
)
232 yield self
.r
.ready
.eq(0)
235 # AXI Stream Definition ----------------------------------------------------------------------------
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
)]
243 axi_layout
+= [("user", user_width
)]
244 stream
.Endpoint
.__init
__(self
, axi_layout
)
246 def get_ios(self
, bus_name
="axi"):
248 Subsignal("tvalid", Pins(1)),
249 Subsignal("tlast", Pins(1)),
250 Subsignal("tready", Pins(1)),
251 Subsignal("tdata", Pins(self
.data_width
)),
254 subsignals
+= [Subsignal("tuser", Pins(self
.user_width
))]
255 ios
= [(bus_name
, 0) + tuple(subsignals
)]
258 def connect_to_pads(self
, pads
, mode
="master"):
259 assert mode
in ["slave", "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
))
267 r
.append(pads
.tuser
.eq(self
.user
))
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
))
274 r
.append(self
.user
.eq(pads
.tuser
))
277 # AXI Bursts to Beats ------------------------------------------------------------------------------
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
285 beat_count
= Signal(8)
286 beat_size
= Signal(8 + 4)
287 beat_offset
= Signal(8 + 4)
288 beat_wrap
= Signal(8 + 4)
291 self
.comb
+= beat_size
.eq(1 << ax_burst
.size
)
292 self
.comb
+= beat_wrap
.eq(ax_burst
.len << ax_burst
.size
)
294 # combinatorial logic
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),
310 If(ax_beat
.valid
& ax_beat
.ready
,
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
)
321 If((ax_burst
.burst
== BURST_WRAP
) & (BURST_WRAP
in capabilities
),
322 If(beat_offset
== beat_wrap
,
330 # AXI to AXI Lite ----------------------------------------------------------------------------------
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
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
347 _data
= Signal(axi
.data_width
)
349 _last_ar_aw_n
= Signal()
351 self
.submodules
.fsm
= fsm
= FSM(reset_state
="IDLE")
353 NextValue(_cmd_done
, 0),
354 If(axi
.ar
.valid
& axi
.aw
.valid
,
355 # If last access was a read, do a write
357 axi
.aw
.connect(ax_burst
),
358 NextValue(_last_ar_aw_n
, 0),
360 # If last access was a write, do a read
362 axi
.ar
.connect(ax_burst
),
363 NextValue(_last_ar_aw_n
, 1),
367 axi
.ar
.connect(ax_burst
),
368 NextValue(_last_ar_aw_n
, 1),
371 axi
.aw
.connect(ax_burst
),
372 NextValue(_last_ar_aw_n
, 0),
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
,
384 NextValue(_cmd_done
, 1)
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
),
395 If(axi
.r
.valid
& axi
.r
.last
& axi
.r
.ready
,
400 # always accept write responses
401 self
.comb
+= axi_lite
.b
.ready
.eq(1)
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
,
410 NextValue(_cmd_done
, 1)
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
),
419 If(axi
.w
.valid
& axi
.w
.last
& axi
.w
.ready
,
420 NextState("WRITE-RESP")
423 fsm
.act("WRITE-RESP",
425 axi
.b
.resp
.eq(RESP_OKAY
),
426 axi
.b
.id.eq(ax_beat
.id),
433 # AXI Lite to Wishbone -----------------------------------------------------------------------------
435 class AXILite2Wishbone(Module
):
436 def __init__(self
, axi_lite
, wishbone
, base_address
=0x00000000):
437 wishbone_adr_shift
= log2_int(axi_lite
.data_width
//8)
438 assert axi_lite
.data_width
== len(wishbone
.dat_r
)
439 assert axi_lite
.address_width
== len(wishbone
.adr
) + wishbone_adr_shift
441 _data
= Signal(axi_lite
.data_width
)
442 _r_addr
= Signal(axi_lite
.address_width
)
443 _w_addr
= Signal(axi_lite
.address_width
)
444 _last_ar_aw_n
= Signal()
445 self
.comb
+= _r_addr
.eq(axi_lite
.ar
.addr
- base_address
)
446 self
.comb
+= _w_addr
.eq(axi_lite
.aw
.addr
- base_address
)
448 self
.submodules
.fsm
= fsm
= FSM(reset_state
="IDLE")
450 If(axi_lite
.ar
.valid
& axi_lite
.aw
.valid
,
451 # If last access was a read, do a write
453 NextValue(_last_ar_aw_n
, 0),
454 NextState("DO-WRITE")
455 # If last access was a write, do a read
457 NextValue(_last_ar_aw_n
, 1),
460 ).Elif(axi_lite
.ar
.valid
,
461 NextValue(_last_ar_aw_n
, 1),
463 ).Elif(axi_lite
.aw
.valid
,
464 NextValue(_last_ar_aw_n
, 0),
465 NextState("DO-WRITE")
471 wishbone
.adr
.eq(_r_addr
[wishbone_adr_shift
:]),
472 wishbone
.sel
.eq(2**len(wishbone
.sel
) - 1),
474 axi_lite
.ar
.ready
.eq(1),
475 NextValue(_data
, wishbone
.dat_r
),
476 NextState("SEND-READ-RESPONSE")
479 fsm
.act("SEND-READ-RESPONSE",
480 axi_lite
.r
.valid
.eq(1),
481 axi_lite
.r
.resp
.eq(RESP_OKAY
),
482 axi_lite
.r
.data
.eq(_data
),
488 wishbone
.stb
.eq(axi_lite
.w
.valid
),
489 wishbone
.cyc
.eq(axi_lite
.w
.valid
),
491 wishbone
.adr
.eq(_w_addr
[wishbone_adr_shift
:]),
492 wishbone
.sel
.eq(axi_lite
.w
.strb
),
493 wishbone
.dat_w
.eq(axi_lite
.w
.data
),
495 axi_lite
.aw
.ready
.eq(1),
496 axi_lite
.w
.ready
.eq(1),
497 NextState("SEND-WRITE-RESPONSE")
500 fsm
.act("SEND-WRITE-RESPONSE",
501 axi_lite
.b
.valid
.eq(1),
502 axi_lite
.b
.resp
.eq(RESP_OKAY
),
508 # AXI to Wishbone ----------------------------------------------------------------------------------
510 class AXI2Wishbone(Module
):
511 def __init__(self
, axi
, wishbone
, base_address
=0x00000000):
512 axi_lite
= AXILiteInterface(axi
.data_width
, axi
.address_width
)
513 axi2axi_lite
= AXI2AXILite(axi
, axi_lite
)
514 axi_lite2wishbone
= AXILite2Wishbone(axi_lite
, wishbone
, base_address
)
515 self
.submodules
+= axi2axi_lite
, axi_lite2wishbone
517 # Wishbone to AXILite ------------------------------------------------------------------------------
519 class Wishbone2AXILite(Module
):
520 def __init__(self
, wishbone
, axi_lite
, base_address
=0x00000000):
521 wishbone_adr_shift
= log2_int(axi_lite
.data_width
//8)
522 assert axi_lite
.data_width
== len(wishbone
.dat_r
)
523 assert axi_lite
.address_width
== len(wishbone
.adr
) + wishbone_adr_shift
526 _data_done
= Signal()
527 _addr
= Signal(len(wishbone
.adr
))
528 self
.comb
+= _addr
.eq(wishbone
.adr
- base_address
//4)
530 self
.submodules
.fsm
= fsm
= FSM(reset_state
="IDLE")
532 NextValue(_cmd_done
, 0),
533 NextValue(_data_done
, 0),
534 If(wishbone
.stb
& wishbone
.cyc
,
544 axi_lite
.aw
.valid
.eq(~_cmd_done
),
545 axi_lite
.aw
.addr
[wishbone_adr_shift
:].eq(_addr
),
546 If(axi_lite
.aw
.valid
& axi_lite
.aw
.ready
,
547 NextValue(_cmd_done
, 1)
550 axi_lite
.w
.valid
.eq(~_data_done
),
551 axi_lite
.w
.data
.eq(wishbone
.dat_w
),
552 axi_lite
.w
.strb
.eq(wishbone
.sel
),
553 If(axi_lite
.w
.valid
& axi_lite
.w
.ready
,
554 NextValue(_data_done
, 1),
557 axi_lite
.b
.ready
.eq(_cmd_done
& _data_done
),
558 If(axi_lite
.b
.valid
& axi_lite
.b
.ready
,
559 If(axi_lite
.b
.resp
== RESP_OKAY
,
569 axi_lite
.ar
.valid
.eq(~_cmd_done
),
570 axi_lite
.ar
.addr
[wishbone_adr_shift
:].eq(_addr
),
571 If(axi_lite
.ar
.valid
& axi_lite
.ar
.ready
,
572 NextValue(_cmd_done
, 1)
575 axi_lite
.r
.ready
.eq(_cmd_done
),
576 If(axi_lite
.r
.valid
& axi_lite
.r
.ready
,
577 If(axi_lite
.r
.resp
== RESP_OKAY
,
578 wishbone
.dat_r
.eq(axi_lite
.r
.data
),
592 # AXILite to CSR -----------------------------------------------------------------------------------
594 def axi_lite_to_simple(axi_lite
, port_adr
, port_dat_r
, port_dat_w
=None, port_we
=None):
595 """Connection of AXILite to simple bus with 1-cycle latency, such as CSR bus or Memory port"""
596 bus_data_width
= axi_lite
.data_width
597 adr_shift
= log2_int(bus_data_width
//8)
600 last_was_read
= Signal()
603 if port_dat_w
is not None:
604 comb
.append(port_dat_w
.eq(axi_lite
.w
.data
))
605 if port_we
is not None:
607 for i
in range(bus_data_width
//8):
608 comb
.append(port_we
[i
].eq(axi_lite
.w
.valid
& axi_lite
.w
.ready
& axi_lite
.w
.strb
[i
]))
610 comb
.append(port_we
.eq(axi_lite
.w
.valid
& axi_lite
.w
.ready
& (axi_lite
.w
.strb
!= 0)))
613 fsm
.act("START-TRANSACTION",
614 # If the last access was a read, do a write, and vice versa
615 If(axi_lite
.aw
.valid
& axi_lite
.ar
.valid
,
616 do_write
.eq(last_was_read
),
617 do_read
.eq(~last_was_read
),
619 do_write
.eq(axi_lite
.aw
.valid
),
620 do_read
.eq(axi_lite
.ar
.valid
),
622 # Start reading/writing immediately not to waste a cycle
624 port_adr
.eq(axi_lite
.aw
.addr
[adr_shift
:]),
626 axi_lite
.aw
.ready
.eq(1),
627 axi_lite
.w
.ready
.eq(1),
628 NextState("SEND-WRITE-RESPONSE")
631 port_adr
.eq(axi_lite
.ar
.addr
[adr_shift
:]),
632 axi_lite
.ar
.ready
.eq(1),
633 NextState("SEND-READ-RESPONSE"),
636 fsm
.act("SEND-READ-RESPONSE",
637 NextValue(last_was_read
, 1),
638 # As long as we have correct address port.dat_r will be valid
639 port_adr
.eq(axi_lite
.ar
.addr
[adr_shift
:]),
640 axi_lite
.r
.data
.eq(port_dat_r
),
641 axi_lite
.r
.resp
.eq(RESP_OKAY
),
642 axi_lite
.r
.valid
.eq(1),
644 NextState("START-TRANSACTION")
647 fsm
.act("SEND-WRITE-RESPONSE",
648 NextValue(last_was_read
, 0),
649 axi_lite
.b
.valid
.eq(1),
650 axi_lite
.b
.resp
.eq(RESP_OKAY
),
652 NextState("START-TRANSACTION")
657 class AXILite2CSR(Module
):
658 def __init__(self
, axi_lite
=None, bus_csr
=None):
660 axi_lite
= AXILiteInterface()
662 bus_csr
= csr_bus
.Interface()
664 self
.axi_lite
= axi_lite
667 fsm
, comb
= axi_lite_to_simple(self
.axi_lite
,
668 port_adr
=self
.csr
.adr
, port_dat_r
=self
.csr
.dat_r
,
669 port_dat_w
=self
.csr
.dat_w
, port_we
=self
.csr
.we
)
670 self
.submodules
.fsm
= fsm
673 # AXILite SRAM -------------------------------------------------------------------------------------
675 class AXILiteSRAM(Module
):
676 def __init__(self
, mem_or_size
, read_only
=None, init
=None, bus
=None):
678 bus
= AXILiteInterface()
681 bus_data_width
= len(self
.bus
.r
.data
)
682 if isinstance(mem_or_size
, Memory
):
683 assert(mem_or_size
.width
<= bus_data_width
)
684 self
.mem
= mem_or_size
686 self
.mem
= Memory(bus_data_width
, mem_or_size
//(bus_data_width
//8), init
=init
)
688 if read_only
is None:
689 if hasattr(self
.mem
, "bus_read_only"):
690 read_only
= self
.mem
.bus_read_only
697 port
= self
.mem
.get_port(write_capable
=not read_only
, we_granularity
=8,
698 mode
=READ_FIRST
if read_only
else WRITE_FIRST
)
699 self
.specials
+= self
.mem
, port
701 # Generate write enable signal
703 self
.comb
+= port
.dat_w
.eq(self
.bus
.w
.data
),
704 self
.comb
+= [port
.we
[i
].eq(self
.bus
.w
.valid
& self
.bus
.w
.ready
& self
.bus
.w
.strb
[i
])
705 for i
in range(bus_data_width
//8)]
708 fsm
, comb
= axi_lite_to_simple(self
.bus
,
709 port_adr
=port
.adr
, port_dat_r
=port
.dat_r
,
710 port_dat_w
=port
.dat_w
if not read_only
else None,
711 port_we
=port
.we
if not read_only
else None)
712 self
.submodules
.fsm
= fsm
715 # AXILite Data Width Converter ---------------------------------------------------------------------
717 class AXILiteDownConverter(Module
):
718 def __init__(self
, master
, slave
):
719 assert isinstance(master
, AXILiteInterface
) and isinstance(slave
, AXILiteInterface
)
720 dw_from
= len(master
.r
.data
)
721 dw_to
= len(slave
.r
.data
)
722 ratio
= dw_from
//dw_to
727 counter
= Signal(max=ratio
)
730 last_was_read
= Signal()
733 resp
= Signal
.like(master
.b
.resp
)
735 # Slave address counter
736 master_align
= log2_int(master
.data_width
//8)
737 slave_align
= log2_int(slave
.data_width
//8)
738 addr_counter
= Signal(master_align
)
739 self
.comb
+= addr_counter
[slave_align
:].eq(counter
)
743 slave
.aw
.addr
.eq(Cat(addr_counter
, master
.aw
.addr
[master_align
:])),
744 Case(counter
, {i
: slave
.w
.data
.eq(master
.w
.data
[i
*dw_to
:]) for i
in range(ratio
)}),
745 Case(counter
, {i
: slave
.w
.strb
.eq(master
.w
.strb
[i
*dw_to
//8:]) for i
in range(ratio
)}),
746 master
.b
.resp
.eq(resp
),
750 # shift the data word
751 r_data
= Signal(dw_from
, reset_less
=True)
752 self
.sync
+= If(slave
.r
.ready
, r_data
.eq(master
.r
.data
))
753 self
.comb
+= master
.r
.data
.eq(Cat(r_data
[dw_to
:], slave
.r
.data
))
756 slave
.ar
.addr
.eq(Cat(addr_counter
, master
.ar
.addr
[master_align
:])),
757 master
.r
.resp
.eq(resp
),
761 fsm
= FSM(reset_state
="IDLE")
762 fsm
= ResetInserter()(fsm
)
763 self
.submodules
.fsm
= fsm
764 self
.comb
+= fsm
.reset
.eq(~
(master
.aw
.valid | master
.ar
.valid
))
767 NextValue(counter
, 0),
768 NextValue(resp
, RESP_OKAY
),
769 # If the last access was a read, do a write, and vice versa
770 If(master
.aw
.valid
& master
.ar
.valid
,
771 do_write
.eq(last_was_read
),
772 do_read
.eq(~last_was_read
),
774 do_write
.eq(master
.aw
.valid
),
775 do_read
.eq(master
.ar
.valid
),
777 # Start reading/writing immediately not to waste a cycle
778 If(do_write
& master
.w
.valid
,
779 NextValue(last_was_read
, 0),
782 NextValue(last_was_read
, 1),
789 skip
.eq(slave
.w
.strb
== 0),
790 slave
.aw
.valid
.eq(~skip
& ~aw_ready
),
791 slave
.w
.valid
.eq(~skip
& ~w_ready
),
793 NextValue(aw_ready
, 1)
796 NextValue(w_ready
, 1)
798 # When skipping, we just increment the counter
800 NextValue(counter
, counter
+ 1),
801 # Corner-case: when the last word is being skipped, we must send the response
802 If(counter
== (ratio
- 1),
803 master
.aw
.ready
.eq(1),
804 master
.w
.ready
.eq(1),
805 NextState("WRITE-RESPONSE-MASTER")
807 # Write current word and wait for write response
808 ).Elif((slave
.aw
.ready | aw_ready
) & (slave
.w
.ready | w_ready
),
809 NextState("WRITE-RESPONSE-SLAVE")
812 fsm
.act("WRITE-RESPONSE-SLAVE",
813 NextValue(aw_ready
, 0),
814 NextValue(w_ready
, 0),
817 # Any errors is sticky, so the first one is always sent
818 If((resp
== RESP_OKAY
) & (slave
.b
.resp
!= RESP_OKAY
),
819 NextValue(resp
, slave
.b
.resp
)
821 If(counter
== (ratio
- 1),
822 master
.aw
.ready
.eq(1),
823 master
.w
.ready
.eq(1),
824 NextState("WRITE-RESPONSE-MASTER")
826 NextValue(counter
, counter
+ 1),
831 fsm
.act("WRITE-RESPONSE-MASTER",
832 NextValue(aw_ready
, 0),
833 NextValue(w_ready
, 0),
834 master
.b
.valid
.eq(1),
842 slave
.ar
.valid
.eq(1),
844 NextState("READ-RESPONSE-SLAVE")
847 fsm
.act("READ-RESPONSE-SLAVE",
849 # Any errors is sticky, so the first one is always sent
850 If((resp
== RESP_OKAY
) & (slave
.b
.resp
!= RESP_OKAY
),
851 NextValue(resp
, slave
.b
.resp
)
853 # On last word acknowledge ar and hold slave.r.valid until we get master.r.ready
854 If(counter
== (ratio
- 1),
855 master
.ar
.ready
.eq(1),
856 NextState("READ-RESPONSE-MASTER")
857 # Acknowledge the response and continue conversion
860 NextValue(counter
, counter
+ 1),
865 fsm
.act("READ-RESPONSE-MASTER",
866 master
.r
.valid
.eq(1),
873 class AXILiteConverter(Module
):
874 """AXILite data width converter"""
875 def __init__(self
, master
, slave
):
881 dw_from
= len(master
.r
.data
)
882 dw_to
= len(slave
.r
.data
)
884 self
.submodules
+= AXILiteDownConverter(master
, slave
)
885 elif dw_from
< dw_to
:
886 raise NotImplementedError("AXILiteUpConverter")
888 self
.comb
+= master
.connect(slave
)
890 # AXILite Timeout ----------------------------------------------------------------------------------
892 class AXILiteTimeout(Module
):
893 """Protect master against slave timeouts (master _has_ to respond correctly)"""
894 def __init__(self
, master
, cycles
):
895 self
.error
= Signal()
901 self
.comb
+= self
.error
.eq(wr_error | rd_error
)
903 wr_timer
= WaitTimer(int(cycles
))
904 rd_timer
= WaitTimer(int(cycles
))
905 self
.submodules
+= wr_timer
, rd_timer
907 def channel_fsm(timer
, wait_cond
, error
, response
):
908 fsm
= FSM(reset_state
="WAIT")
910 timer
.wait
.eq(wait_cond
),
911 # done is updated in `sync`, so we must make sure that `ready` has not been issued
912 # by slave during that single cycle, by checking `timer.wait`
913 If(timer
.done
& timer
.wait
,
918 fsm
.act("RESPOND", *response
)
921 self
.submodules
.wr_fsm
= channel_fsm(
923 wait_cond
= (master
.aw
.valid
& ~master
.aw
.ready
) |
(master
.w
.valid
& ~master
.w
.ready
),
926 master
.aw
.ready
.eq(master
.aw
.valid
),
927 master
.w
.ready
.eq(master
.w
.valid
),
928 master
.b
.valid
.eq(~master
.aw
.valid
& ~master
.w
.valid
),
929 master
.b
.resp
.eq(RESP_SLVERR
),
930 If(master
.b
.valid
& master
.b
.ready
,
935 self
.submodules
.rd_fsm
= channel_fsm(
937 wait_cond
= master
.ar
.valid
& ~master
.ar
.ready
,
940 master
.ar
.ready
.eq(master
.ar
.valid
),
941 master
.r
.valid
.eq(~master
.ar
.valid
),
942 master
.r
.resp
.eq(RESP_SLVERR
),
943 master
.r
.data
.eq(2**len(master
.r
.data
) - 1),
944 If(master
.r
.valid
& master
.r
.ready
,
949 # AXILite Interconnect -----------------------------------------------------------------------------
951 class AXILiteInterconnectPointToPoint(Module
):
952 def __init__(self
, master
, slave
):
953 self
.comb
+= master
.connect(slave
)
956 class AXILiteRequestCounter(Module
):
957 def __init__(self
, request
, response
, max_requests
=256):
958 self
.counter
= counter
= Signal(max=max_requests
)
959 self
.full
= full
= Signal()
960 self
.empty
= empty
= Signal()
961 self
.stall
= stall
= Signal()
962 self
.ready
= self
.empty
965 full
.eq(counter
== max_requests
- 1),
966 empty
.eq(counter
== 0),
967 stall
.eq(request
& full
),
971 If(request
& response
,
973 ).Elif(request
& ~full
,
974 counter
.eq(counter
+ 1)
975 ).Elif(response
& ~empty
,
976 counter
.eq(counter
- 1)
980 class AXILiteArbiter(Module
):
983 Arbitrate between master interfaces and connect one to the target.
984 New master will not be selected until all requests have been responded to.
985 Arbitration for write and read channels is done separately.
987 def __init__(self
, masters
, target
):
988 self
.submodules
.rr_write
= roundrobin
.RoundRobin(len(masters
), roundrobin
.SP_CE
)
989 self
.submodules
.rr_read
= roundrobin
.RoundRobin(len(masters
), roundrobin
.SP_CE
)
991 def get_sig(interface
, channel
, name
):
992 return getattr(getattr(interface
, channel
), name
)
994 # mux master->slave signals
995 for channel
, name
, direction
in target
.layout_flat():
996 rr
= self
.rr_write
if channel
in ["aw", "w", "b"] else self
.rr_read
997 if direction
== DIR_M_TO_S
:
998 choices
= Array(get_sig(m
, channel
, name
) for m
in masters
)
999 self
.comb
+= get_sig(target
, channel
, name
).eq(choices
[rr
.grant
])
1001 # connect slave->master signals
1002 for channel
, name
, direction
in target
.layout_flat():
1003 rr
= self
.rr_write
if channel
in ["aw", "w", "b"] else self
.rr_read
1004 if direction
== DIR_S_TO_M
:
1005 source
= get_sig(target
, channel
, name
)
1006 for i
, m
in enumerate(masters
):
1007 dest
= get_sig(m
, channel
, name
)
1009 self
.comb
+= dest
.eq(source
& (rr
.grant
== i
))
1011 self
.comb
+= dest
.eq(source
)
1013 # allow to change rr.grant only after all requests from a master have been responded to
1014 self
.submodules
.wr_lock
= wr_lock
= AXILiteRequestCounter(
1015 request
=target
.aw
.valid
& target
.aw
.ready
, response
=target
.b
.valid
& target
.b
.ready
)
1016 self
.submodules
.rd_lock
= rd_lock
= AXILiteRequestCounter(
1017 request
=target
.ar
.valid
& target
.ar
.ready
, response
=target
.r
.valid
& target
.r
.ready
)
1019 # switch to next request only if there are no responses pending
1021 self
.rr_write
.ce
.eq(~
(target
.aw
.valid | target
.w
.valid | target
.b
.valid
) & wr_lock
.ready
),
1022 self
.rr_read
.ce
.eq(~
(target
.ar
.valid | target
.r
.valid
) & rd_lock
.ready
),
1025 # connect bus requests to round-robin selectors
1027 self
.rr_write
.request
.eq(Cat(*[m
.aw
.valid | m
.w
.valid | m
.b
.valid
for m
in masters
])),
1028 self
.rr_read
.request
.eq(Cat(*[m
.ar
.valid | m
.r
.valid
for m
in masters
])),
1031 class AXILiteDecoder(Module
):
1033 slaves: [(decoder, slave), ...]
1034 List of slaves with address decoders, where `decoder` is a function:
1035 decoder(Signal(address_width - log2(data_width//8))) -> Signal(1)
1036 that returns 1 when the slave is selected and 0 otherwise.
1039 __doc__
= """AXI Lite decoder
1041 Decode master access to particular slave based on its decoder function.
1044 """.format(slaves
=_doc_slaves
)
1046 def __init__(self
, master
, slaves
, register
=False):
1047 # TODO: unused register argument
1048 addr_shift
= log2_int(master
.data_width
//8)
1051 "write": {"aw", "w", "b"},
1052 "read": {"ar", "r"},
1054 # reverse mapping: directions[channel] -> "write"/"read"
1055 directions
= {ch
: d
for d
, chs
in channels
.items() for ch
in chs
}
1057 def new_slave_sel():
1058 return {"write": Signal(len(slaves
)), "read": Signal(len(slaves
))}
1060 slave_sel_dec
= new_slave_sel()
1061 slave_sel_reg
= new_slave_sel()
1062 slave_sel
= new_slave_sel()
1064 # we need to hold the slave selected until all responses come back
1065 # TODO: we could reuse arbiter counters
1067 "write": AXILiteRequestCounter(
1068 request
=master
.aw
.valid
& master
.aw
.ready
,
1069 response
=master
.b
.valid
& master
.b
.ready
),
1070 "read": AXILiteRequestCounter(
1071 request
=master
.ar
.valid
& master
.ar
.ready
,
1072 response
=master
.r
.valid
& master
.r
.ready
),
1074 self
.submodules
+= locks
.values()
1076 def get_sig(interface
, channel
, name
):
1077 return getattr(getattr(interface
, channel
), name
)
1081 # decode slave addresses
1082 for i
, (decoder
, bus
) in enumerate(slaves
):
1084 slave_sel_dec
["write"][i
].eq(decoder(master
.aw
.addr
[addr_shift
:])),
1085 slave_sel_dec
["read"][i
].eq(decoder(master
.ar
.addr
[addr_shift
:])),
1088 # change the current selection only when we've got all responses
1089 for channel
in locks
.keys():
1090 self
.sync
+= If(locks
[channel
].ready
, slave_sel_reg
[channel
].eq(slave_sel_dec
[channel
]))
1091 # we have to cut the delaying select
1092 for ch
, final
in slave_sel
.items():
1093 self
.comb
+= If(locks
[ch
].ready
,
1094 final
.eq(slave_sel_dec
[ch
])
1096 final
.eq(slave_sel_reg
[ch
])
1099 # connect master->slaves signals except valid/ready
1100 for i
, (_
, slave
) in enumerate(slaves
):
1101 for channel
, name
, direction
in master
.layout_flat():
1102 if direction
== DIR_M_TO_S
:
1103 src
= get_sig(master
, channel
, name
)
1104 dst
= get_sig(slave
, channel
, name
)
1105 # mask master control signals depending on slave selection
1106 if name
in ["valid", "ready"]:
1107 src
= src
& slave_sel
[directions
[channel
]][i
]
1108 self
.comb
+= dst
.eq(src
)
1110 # connect slave->master signals masking not selected slaves
1111 for channel
, name
, direction
in master
.layout_flat():
1112 if direction
== DIR_S_TO_M
:
1113 dst
= get_sig(master
, channel
, name
)
1115 for i
, (_
, slave
) in enumerate(slaves
):
1116 src
= get_sig(slave
, channel
, name
)
1117 # mask depending on channel
1118 mask
= Replicate(slave_sel
[directions
[channel
]][i
], len(dst
))
1119 masked
.append(src
& mask
)
1120 self
.comb
+= dst
.eq(reduce(or_
, masked
))
1122 class AXILiteInterconnectShared(Module
):
1123 __doc__
= """AXI Lite shared interconnect
1126 """.format(slaves
=AXILiteDecoder
._doc
_slaves
)
1128 def __init__(self
, masters
, slaves
, register
=False, timeout_cycles
=1e6
):
1130 shared
= AXILiteInterface()
1131 self
.submodules
.arbiter
= AXILiteArbiter(masters
, shared
)
1132 self
.submodules
.decoder
= AXILiteDecoder(shared
, slaves
)
1133 if timeout_cycles
is not None:
1134 self
.submodules
.timeout
= AXILiteTimeout(shared
, timeout_cycles
)
1136 class AXILiteCrossbar(Module
):
1137 __doc__
= """AXI Lite crossbar
1139 MxN crossbar for M masters and N slaves.
1142 """.format(slaves
=AXILiteDecoder
._doc
_slaves
)
1144 def __init__(self
, masters
, slaves
, register
=False, timeout_cycles
=1e6
):
1145 matches
, busses
= zip(*slaves
)
1146 access_m_s
= [[AXILiteInterface() for j
in slaves
] for i
in masters
] # a[master][slave]
1147 access_s_m
= list(zip(*access_m_s
)) # a[slave][master]
1148 # decode each master into its access row
1149 for slaves
, master
in zip(access_m_s
, masters
):
1150 slaves
= list(zip(matches
, slaves
))
1151 self
.submodules
+= AXILiteDecoder(master
, slaves
, register
)
1152 # arbitrate each access column onto its slave
1153 for masters
, bus
in zip(access_s_m
, busses
):
1154 self
.submodules
+= AXILiteArbiter(masters
, bus
)