a1fd90b6ed4200dc9ce7faea90231901749c04f1
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
, keep
=None, omit
=None):
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
, keep
=keep
, omit
=omit
))
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
, **kwargs
):
111 return _connect_axi(self
, slave
, **kwargs
)
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
, **kwargs
):
187 return _connect_axi(self
, slave
, **kwargs
)
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 _AXILiteDownConverterWrite(Module
):
718 def __init__(self
, master
, slave
):
719 assert isinstance(master
, AXILiteInterface
) and isinstance(slave
, AXILiteInterface
)
720 dw_from
= len(master
.w
.data
)
721 dw_to
= len(slave
.w
.data
)
722 ratio
= dw_from
//dw_to
723 master_align
= log2_int(master
.data_width
//8)
724 slave_align
= log2_int(slave
.data_width
//8)
727 counter
= Signal(max=ratio
)
730 resp
= Signal
.like(master
.b
.resp
)
731 addr_counter
= Signal(master_align
)
735 # Slave address counter
736 self
.comb
+= addr_counter
[slave_align
:].eq(counter
)
740 slave
.aw
.addr
.eq(Cat(addr_counter
, master
.aw
.addr
[master_align
:])),
741 Case(counter
, {i
: slave
.w
.data
.eq(master
.w
.data
[i
*dw_to
:]) for i
in range(ratio
)}),
742 Case(counter
, {i
: slave
.w
.strb
.eq(master
.w
.strb
[i
*dw_to
//8:]) for i
in range(ratio
)}),
743 master
.b
.resp
.eq(resp
),
747 fsm
= FSM(reset_state
="IDLE")
748 fsm
= ResetInserter()(fsm
)
749 self
.submodules
.fsm
= fsm
750 # Reset the converter state if master breaks a request, we can do that as
751 # aw.valid and w.valid are kept high in CONVERT and RESPOND-SLAVE, and
752 # acknowledged only when moving to RESPOND-MASTER, and then b.valid is 1
753 self
.comb
+= fsm
.reset
.eq(~
((master
.aw
.valid | master
.w
.valid
) | master
.b
.valid
))
756 NextValue(counter
, 0),
757 NextValue(resp
, RESP_OKAY
),
758 If(master
.aw
.valid
& master
.w
.valid
,
763 skip
.eq(slave
.w
.strb
== 0),
764 slave
.aw
.valid
.eq(~skip
& ~aw_ready
),
765 slave
.w
.valid
.eq(~skip
& ~w_ready
),
767 NextValue(aw_ready
, 1)
770 NextValue(w_ready
, 1)
772 # When skipping, we just increment the counter
774 NextValue(counter
, counter
+ 1),
775 # Corner-case: when the last word is being skipped, we must send the response
776 If(counter
== (ratio
- 1),
777 master
.aw
.ready
.eq(1),
778 master
.w
.ready
.eq(1),
779 NextState("RESPOND-MASTER")
781 # Write current word and wait for write response
782 ).Elif((slave
.aw
.ready | aw_ready
) & (slave
.w
.ready | w_ready
),
783 NextState("RESPOND-SLAVE")
786 fsm
.act("RESPOND-SLAVE",
787 NextValue(aw_ready
, 0),
788 NextValue(w_ready
, 0),
791 # Errors are sticky, so the first one is always sent
792 If((resp
== RESP_OKAY
) & (slave
.b
.resp
!= RESP_OKAY
),
793 NextValue(resp
, slave
.b
.resp
)
795 If(counter
== (ratio
- 1),
796 master
.aw
.ready
.eq(1),
797 master
.w
.ready
.eq(1),
798 NextState("RESPOND-MASTER")
800 NextValue(counter
, counter
+ 1),
805 fsm
.act("RESPOND-MASTER",
806 NextValue(aw_ready
, 0),
807 NextValue(w_ready
, 0),
808 master
.b
.valid
.eq(1),
814 class _AXILiteDownConverterRead(Module
):
815 def __init__(self
, master
, slave
):
816 assert isinstance(master
, AXILiteInterface
) and isinstance(slave
, AXILiteInterface
)
817 dw_from
= len(master
.r
.data
)
818 dw_to
= len(slave
.r
.data
)
819 ratio
= dw_from
//dw_to
820 master_align
= log2_int(master
.data_width
//8)
821 slave_align
= log2_int(slave
.data_width
//8)
824 counter
= Signal(max=ratio
)
825 resp
= Signal
.like(master
.r
.resp
)
826 addr_counter
= Signal(master_align
)
830 # Slave address counter
831 self
.comb
+= addr_counter
[slave_align
:].eq(counter
)
834 # shift the data word
835 r_data
= Signal(dw_from
, reset_less
=True)
836 self
.sync
+= If(slave
.r
.ready
, r_data
.eq(master
.r
.data
))
837 self
.comb
+= master
.r
.data
.eq(Cat(r_data
[dw_to
:], slave
.r
.data
))
840 slave
.ar
.addr
.eq(Cat(addr_counter
, master
.ar
.addr
[master_align
:])),
841 master
.r
.resp
.eq(resp
),
845 fsm
= FSM(reset_state
="IDLE")
846 fsm
= ResetInserter()(fsm
)
847 self
.submodules
.fsm
= fsm
848 # Reset the converter state if master breaks a request, we can do that as
849 # ar.valid is high in CONVERT and RESPOND-SLAVE, and r.valid in RESPOND-MASTER
850 self
.comb
+= fsm
.reset
.eq(~
(master
.ar
.valid | master
.r
.valid
))
853 NextValue(counter
, 0),
854 NextValue(resp
, RESP_OKAY
),
860 slave
.ar
.valid
.eq(1),
862 NextState("RESPOND-SLAVE")
865 fsm
.act("RESPOND-SLAVE",
867 # Errors are sticky, so the first one is always sent
868 If((resp
== RESP_OKAY
) & (slave
.r
.resp
!= RESP_OKAY
),
869 NextValue(resp
, slave
.r
.resp
)
871 # On last word acknowledge ar and hold slave.r.valid until we get master.r.ready
872 If(counter
== (ratio
- 1),
873 master
.ar
.ready
.eq(1),
874 NextState("RESPOND-MASTER")
875 # Acknowledge the response and continue conversion
878 NextValue(counter
, counter
+ 1),
883 fsm
.act("RESPOND-MASTER",
884 master
.r
.valid
.eq(1),
891 class AXILiteDownConverter(Module
):
892 def __init__(self
, master
, slave
):
893 self
.submodules
.write
= _AXILiteDownConverterWrite(master
, slave
)
894 self
.submodules
.read
= _AXILiteDownConverterRead(master
, slave
)
896 class AXILiteUpConverter(Module
):
897 # TODO: we could try joining multiple master accesses into single slave access
898 # would reuqire checking if address changes and a way to flush on single access
899 def __init__(self
, master
, slave
):
900 assert isinstance(master
, AXILiteInterface
) and isinstance(slave
, AXILiteInterface
)
901 dw_from
= len(master
.r
.data
)
902 dw_to
= len(slave
.r
.data
)
903 ratio
= dw_to
//dw_from
904 master_align
= log2_int(master
.data_width
//8)
905 slave_align
= log2_int(slave
.data_width
//8)
907 wr_word
= Signal(log2_int(ratio
))
908 rd_word
= Signal(log2_int(ratio
))
909 wr_word_r
= Signal(log2_int(ratio
))
910 rd_word_r
= Signal(log2_int(ratio
))
914 self
.comb
+= master
.connect(slave
, omit
={"addr", "strb", "data"})
918 slave
.aw
.addr
[slave_align
:].eq(master
.aw
.addr
[slave_align
:]),
919 slave
.ar
.addr
[slave_align
:].eq(master
.ar
.addr
[slave_align
:]),
923 wr_cases
, rd_cases
= {}, {}
924 for i
in range(ratio
):
925 strb_from
= i
* dw_from
//8
926 strb_to
= (i
+1) * dw_from
//8
927 data_from
= i
* dw_from
928 data_to
= (i
+1) * dw_from
930 slave
.w
.strb
[strb_from
:strb_to
].eq(master
.w
.strb
),
931 slave
.w
.data
[data_from
:data_to
].eq(master
.w
.data
),
934 master
.r
.data
.eq(slave
.r
.data
[data_from
:data_to
]),
937 # Switch current word based on the last valid master address
938 self
.sync
+= If(master
.aw
.valid
, wr_word_r
.eq(wr_word
))
939 self
.sync
+= If(master
.ar
.valid
, rd_word_r
.eq(rd_word
))
941 Case(master
.aw
.valid
, {
942 0: wr_word
.eq(wr_word_r
),
943 1: wr_word
.eq(master
.aw
.addr
[master_align
:slave_align
]),
945 Case(master
.ar
.valid
, {
946 0: rd_word
.eq(rd_word_r
),
947 1: rd_word
.eq(master
.ar
.addr
[master_align
:slave_align
]),
951 self
.comb
+= Case(wr_word
, wr_cases
)
952 self
.comb
+= Case(rd_word
, rd_cases
)
954 class AXILiteConverter(Module
):
955 """AXILite data width converter"""
956 def __init__(self
, master
, slave
):
962 dw_from
= len(master
.r
.data
)
963 dw_to
= len(slave
.r
.data
)
965 self
.submodules
+= AXILiteDownConverter(master
, slave
)
966 elif dw_from
< dw_to
:
967 self
.submodules
+= AXILiteUpConverter(master
, slave
)
969 self
.comb
+= master
.connect(slave
)
971 # AXILite Timeout ----------------------------------------------------------------------------------
973 class AXILiteTimeout(Module
):
974 """Protect master against slave timeouts (master _has_ to respond correctly)"""
975 def __init__(self
, master
, cycles
):
976 self
.error
= Signal()
982 self
.comb
+= self
.error
.eq(wr_error | rd_error
)
984 wr_timer
= WaitTimer(int(cycles
))
985 rd_timer
= WaitTimer(int(cycles
))
986 self
.submodules
+= wr_timer
, rd_timer
988 def channel_fsm(timer
, wait_cond
, error
, response
):
989 fsm
= FSM(reset_state
="WAIT")
991 timer
.wait
.eq(wait_cond
),
992 # done is updated in `sync`, so we must make sure that `ready` has not been issued
993 # by slave during that single cycle, by checking `timer.wait`
994 If(timer
.done
& timer
.wait
,
999 fsm
.act("RESPOND", *response
)
1002 self
.submodules
.wr_fsm
= channel_fsm(
1004 wait_cond
= (master
.aw
.valid
& ~master
.aw
.ready
) |
(master
.w
.valid
& ~master
.w
.ready
),
1007 master
.aw
.ready
.eq(master
.aw
.valid
),
1008 master
.w
.ready
.eq(master
.w
.valid
),
1009 master
.b
.valid
.eq(~master
.aw
.valid
& ~master
.w
.valid
),
1010 master
.b
.resp
.eq(RESP_SLVERR
),
1011 If(master
.b
.valid
& master
.b
.ready
,
1016 self
.submodules
.rd_fsm
= channel_fsm(
1018 wait_cond
= master
.ar
.valid
& ~master
.ar
.ready
,
1021 master
.ar
.ready
.eq(master
.ar
.valid
),
1022 master
.r
.valid
.eq(~master
.ar
.valid
),
1023 master
.r
.resp
.eq(RESP_SLVERR
),
1024 master
.r
.data
.eq(2**len(master
.r
.data
) - 1),
1025 If(master
.r
.valid
& master
.r
.ready
,
1030 # AXILite Interconnect -----------------------------------------------------------------------------
1032 class _AXILiteRequestCounter(Module
):
1033 def __init__(self
, request
, response
, max_requests
=256):
1034 self
.counter
= counter
= Signal(max=max_requests
)
1035 self
.full
= full
= Signal()
1036 self
.empty
= empty
= Signal()
1037 self
.stall
= stall
= Signal()
1038 self
.ready
= self
.empty
1041 full
.eq(counter
== max_requests
- 1),
1042 empty
.eq(counter
== 0),
1043 stall
.eq(request
& full
),
1047 If(request
& response
,
1049 ).Elif(request
& ~full
,
1050 counter
.eq(counter
+ 1)
1051 ).Elif(response
& ~empty
,
1052 counter
.eq(counter
- 1)
1056 class AXILiteInterconnectPointToPoint(Module
):
1057 def __init__(self
, master
, slave
):
1058 self
.comb
+= master
.connect(slave
)
1060 class AXILiteArbiter(Module
):
1063 Arbitrate between master interfaces and connect one to the target.
1064 New master will not be selected until all requests have been responded to.
1065 Arbitration for write and read channels is done separately.
1067 def __init__(self
, masters
, target
):
1068 self
.submodules
.rr_write
= roundrobin
.RoundRobin(len(masters
), roundrobin
.SP_CE
)
1069 self
.submodules
.rr_read
= roundrobin
.RoundRobin(len(masters
), roundrobin
.SP_CE
)
1071 def get_sig(interface
, channel
, name
):
1072 return getattr(getattr(interface
, channel
), name
)
1074 # mux master->slave signals
1075 for channel
, name
, direction
in target
.layout_flat():
1076 rr
= self
.rr_write
if channel
in ["aw", "w", "b"] else self
.rr_read
1077 if direction
== DIR_M_TO_S
:
1078 choices
= Array(get_sig(m
, channel
, name
) for m
in masters
)
1079 self
.comb
+= get_sig(target
, channel
, name
).eq(choices
[rr
.grant
])
1081 # connect slave->master signals
1082 for channel
, name
, direction
in target
.layout_flat():
1083 rr
= self
.rr_write
if channel
in ["aw", "w", "b"] else self
.rr_read
1084 if direction
== DIR_S_TO_M
:
1085 source
= get_sig(target
, channel
, name
)
1086 for i
, m
in enumerate(masters
):
1087 dest
= get_sig(m
, channel
, name
)
1089 self
.comb
+= dest
.eq(source
& (rr
.grant
== i
))
1091 self
.comb
+= dest
.eq(source
)
1093 # allow to change rr.grant only after all requests from a master have been responded to
1094 self
.submodules
.wr_lock
= wr_lock
= _AXILiteRequestCounter(
1095 request
=target
.aw
.valid
& target
.aw
.ready
, response
=target
.b
.valid
& target
.b
.ready
)
1096 self
.submodules
.rd_lock
= rd_lock
= _AXILiteRequestCounter(
1097 request
=target
.ar
.valid
& target
.ar
.ready
, response
=target
.r
.valid
& target
.r
.ready
)
1099 # switch to next request only if there are no responses pending
1101 self
.rr_write
.ce
.eq(~
(target
.aw
.valid | target
.w
.valid | target
.b
.valid
) & wr_lock
.ready
),
1102 self
.rr_read
.ce
.eq(~
(target
.ar
.valid | target
.r
.valid
) & rd_lock
.ready
),
1105 # connect bus requests to round-robin selectors
1107 self
.rr_write
.request
.eq(Cat(*[m
.aw
.valid | m
.w
.valid | m
.b
.valid
for m
in masters
])),
1108 self
.rr_read
.request
.eq(Cat(*[m
.ar
.valid | m
.r
.valid
for m
in masters
])),
1111 class AXILiteDecoder(Module
):
1113 slaves: [(decoder, slave), ...]
1114 List of slaves with address decoders, where `decoder` is a function:
1115 decoder(Signal(address_width - log2(data_width//8))) -> Signal(1)
1116 that returns 1 when the slave is selected and 0 otherwise.
1119 __doc__
= """AXI Lite decoder
1121 Decode master access to particular slave based on its decoder function.
1124 """.format(slaves
=_doc_slaves
)
1126 def __init__(self
, master
, slaves
, register
=False):
1127 # TODO: unused register argument
1128 addr_shift
= log2_int(master
.data_width
//8)
1131 "write": {"aw", "w", "b"},
1132 "read": {"ar", "r"},
1134 # reverse mapping: directions[channel] -> "write"/"read"
1135 directions
= {ch
: d
for d
, chs
in channels
.items() for ch
in chs
}
1137 def new_slave_sel():
1138 return {"write": Signal(len(slaves
)), "read": Signal(len(slaves
))}
1140 slave_sel_dec
= new_slave_sel()
1141 slave_sel_reg
= new_slave_sel()
1142 slave_sel
= new_slave_sel()
1144 # we need to hold the slave selected until all responses come back
1145 # TODO: we could reuse arbiter counters
1147 "write": _AXILiteRequestCounter(
1148 request
=master
.aw
.valid
& master
.aw
.ready
,
1149 response
=master
.b
.valid
& master
.b
.ready
),
1150 "read": _AXILiteRequestCounter(
1151 request
=master
.ar
.valid
& master
.ar
.ready
,
1152 response
=master
.r
.valid
& master
.r
.ready
),
1154 self
.submodules
+= locks
.values()
1156 def get_sig(interface
, channel
, name
):
1157 return getattr(getattr(interface
, channel
), name
)
1161 # decode slave addresses
1162 for i
, (decoder
, bus
) in enumerate(slaves
):
1164 slave_sel_dec
["write"][i
].eq(decoder(master
.aw
.addr
[addr_shift
:])),
1165 slave_sel_dec
["read"][i
].eq(decoder(master
.ar
.addr
[addr_shift
:])),
1168 # change the current selection only when we've got all responses
1169 for channel
in locks
.keys():
1170 self
.sync
+= If(locks
[channel
].ready
, slave_sel_reg
[channel
].eq(slave_sel_dec
[channel
]))
1171 # we have to cut the delaying select
1172 for ch
, final
in slave_sel
.items():
1173 self
.comb
+= If(locks
[ch
].ready
,
1174 final
.eq(slave_sel_dec
[ch
])
1176 final
.eq(slave_sel_reg
[ch
])
1179 # connect master->slaves signals except valid/ready
1180 for i
, (_
, slave
) in enumerate(slaves
):
1181 for channel
, name
, direction
in master
.layout_flat():
1182 if direction
== DIR_M_TO_S
:
1183 src
= get_sig(master
, channel
, name
)
1184 dst
= get_sig(slave
, channel
, name
)
1185 # mask master control signals depending on slave selection
1186 if name
in ["valid", "ready"]:
1187 src
= src
& slave_sel
[directions
[channel
]][i
]
1188 self
.comb
+= dst
.eq(src
)
1190 # connect slave->master signals masking not selected slaves
1191 for channel
, name
, direction
in master
.layout_flat():
1192 if direction
== DIR_S_TO_M
:
1193 dst
= get_sig(master
, channel
, name
)
1195 for i
, (_
, slave
) in enumerate(slaves
):
1196 src
= get_sig(slave
, channel
, name
)
1197 # mask depending on channel
1198 mask
= Replicate(slave_sel
[directions
[channel
]][i
], len(dst
))
1199 masked
.append(src
& mask
)
1200 self
.comb
+= dst
.eq(reduce(or_
, masked
))
1202 class AXILiteInterconnectShared(Module
):
1203 __doc__
= """AXI Lite shared interconnect
1206 """.format(slaves
=AXILiteDecoder
._doc
_slaves
)
1208 def __init__(self
, masters
, slaves
, register
=False, timeout_cycles
=1e6
):
1210 shared
= AXILiteInterface()
1211 self
.submodules
.arbiter
= AXILiteArbiter(masters
, shared
)
1212 self
.submodules
.decoder
= AXILiteDecoder(shared
, slaves
)
1213 if timeout_cycles
is not None:
1214 self
.submodules
.timeout
= AXILiteTimeout(shared
, timeout_cycles
)
1216 class AXILiteCrossbar(Module
):
1217 __doc__
= """AXI Lite crossbar
1219 MxN crossbar for M masters and N slaves.
1222 """.format(slaves
=AXILiteDecoder
._doc
_slaves
)
1224 def __init__(self
, masters
, slaves
, register
=False, timeout_cycles
=1e6
):
1225 matches
, busses
= zip(*slaves
)
1226 access_m_s
= [[AXILiteInterface() for j
in slaves
] for i
in masters
] # a[master][slave]
1227 access_s_m
= list(zip(*access_m_s
)) # a[slave][master]
1228 # decode each master into its access row
1229 for slaves
, master
in zip(access_m_s
, masters
):
1230 slaves
= list(zip(matches
, slaves
))
1231 self
.submodules
+= AXILiteDecoder(master
, slaves
, register
)
1232 # arbitrate each access column onto its slave
1233 for masters
, bus
in zip(access_s_m
, busses
):
1234 self
.submodules
+= AXILiteArbiter(masters
, bus
)