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 AXI ----------------------------------------------------------------------------------
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
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
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
463 axi
.aw
.id.eq(write_id
),
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
),
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
),
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
),
480 axi
.ar
.size
.eq(burst_size
),
482 axi
.ar
.prot
.eq(prot
),
483 axi
.ar
.cache
.eq(0b0011),
485 axi
.ar
.id.eq(read_id
),
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
),
493 # AXI Lite to Wishbone -----------------------------------------------------------------------------
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
))
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
)
509 self
.submodules
.fsm
= fsm
= FSM(reset_state
="IDLE")
511 If(axi_lite
.ar
.valid
& axi_lite
.aw
.valid
,
512 # If last access was a read, do a write
514 NextValue(_last_ar_aw_n
, 0),
515 NextState("DO-WRITE")
516 # If last access was a write, do a read
518 NextValue(_last_ar_aw_n
, 1),
521 ).Elif(axi_lite
.ar
.valid
,
522 NextValue(_last_ar_aw_n
, 1),
524 ).Elif(axi_lite
.aw
.valid
,
525 NextValue(_last_ar_aw_n
, 0),
526 NextState("DO-WRITE")
532 wishbone
.adr
.eq(_r_addr
[wishbone_adr_shift
:]),
533 wishbone
.sel
.eq(2**len(wishbone
.sel
) - 1),
535 axi_lite
.ar
.ready
.eq(1),
536 NextValue(_data
, wishbone
.dat_r
),
537 NextState("SEND-READ-RESPONSE")
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
),
549 wishbone
.stb
.eq(axi_lite
.w
.valid
),
550 wishbone
.cyc
.eq(axi_lite
.w
.valid
),
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
),
556 axi_lite
.aw
.ready
.eq(1),
557 axi_lite
.w
.ready
.eq(1),
558 NextState("SEND-WRITE-RESPONSE")
561 fsm
.act("SEND-WRITE-RESPONSE",
562 axi_lite
.b
.valid
.eq(1),
563 axi_lite
.b
.resp
.eq(RESP_OKAY
),
569 # AXI to Wishbone ----------------------------------------------------------------------------------
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
578 # Wishbone to AXILite ------------------------------------------------------------------------------
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
))
588 _data_done
= Signal()
589 _addr
= Signal(len(wishbone
.adr
))
590 self
.comb
+= _addr
.eq(wishbone
.adr
- base_address
//4)
592 self
.submodules
.fsm
= fsm
= FSM(reset_state
="IDLE")
594 NextValue(_cmd_done
, 0),
595 NextValue(_data_done
, 0),
596 If(wishbone
.stb
& wishbone
.cyc
,
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)
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),
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
,
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)
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
),
654 # Wishbone to AXI ----------------------------------------------------------------------------------
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
663 # AXILite to CSR -----------------------------------------------------------------------------------
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)
671 last_was_read
= Signal()
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:
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
]))
681 comb
.append(port_we
.eq(axi_lite
.w
.valid
& axi_lite
.w
.ready
& (axi_lite
.w
.strb
!= 0)))
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
),
690 do_write
.eq(axi_lite
.aw
.valid
),
691 do_read
.eq(axi_lite
.ar
.valid
),
693 # Start reading/writing immediately not to waste a cycle
695 port_adr
.eq(axi_lite
.aw
.addr
[adr_shift
:]),
697 axi_lite
.aw
.ready
.eq(1),
698 axi_lite
.w
.ready
.eq(1),
699 NextState("SEND-WRITE-RESPONSE")
702 port_adr
.eq(axi_lite
.ar
.addr
[adr_shift
:]),
703 axi_lite
.ar
.ready
.eq(1),
704 NextState("SEND-READ-RESPONSE"),
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),
715 NextState("START-TRANSACTION")
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
),
723 NextState("START-TRANSACTION")
728 class AXILite2CSR(Module
):
729 def __init__(self
, axi_lite
=None, bus_csr
=None):
731 axi_lite
= AXILiteInterface()
733 bus_csr
= csr_bus
.Interface()
735 self
.axi_lite
= axi_lite
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
744 # AXILite SRAM -------------------------------------------------------------------------------------
746 class AXILiteSRAM(Module
):
747 def __init__(self
, mem_or_size
, read_only
=None, init
=None, bus
=None):
749 bus
= AXILiteInterface()
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
757 self
.mem
= Memory(bus_data_width
, mem_or_size
//(bus_data_width
//8), init
=init
)
759 if read_only
is None:
760 if hasattr(self
.mem
, "bus_read_only"):
761 read_only
= self
.mem
.bus_read_only
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
772 # Generate write enable signal
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)]
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
786 # AXILite Data Width Converter ---------------------------------------------------------------------
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)
798 counter
= Signal(max=ratio
)
801 resp
= Signal
.like(master
.b
.resp
)
802 addr_counter
= Signal(master_align
)
806 # Slave address counter
807 self
.comb
+= addr_counter
[slave_align
:].eq(counter
)
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
),
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
))
827 NextValue(counter
, 0),
828 NextValue(resp
, RESP_OKAY
),
829 If(master
.aw
.valid
& master
.w
.valid
,
834 skip
.eq(slave
.w
.strb
== 0),
835 slave
.aw
.valid
.eq(~skip
& ~aw_ready
),
836 slave
.w
.valid
.eq(~skip
& ~w_ready
),
838 NextValue(aw_ready
, 1)
841 NextValue(w_ready
, 1)
843 # When skipping, we just increment the counter
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")
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")
857 fsm
.act("RESPOND-SLAVE",
858 NextValue(aw_ready
, 0),
859 NextValue(w_ready
, 0),
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
)
866 If(counter
== (ratio
- 1),
867 master
.aw
.ready
.eq(1),
868 master
.w
.ready
.eq(1),
869 NextState("RESPOND-MASTER")
871 NextValue(counter
, counter
+ 1),
876 fsm
.act("RESPOND-MASTER",
877 NextValue(aw_ready
, 0),
878 NextValue(w_ready
, 0),
879 master
.b
.valid
.eq(1),
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)
895 counter
= Signal(max=ratio
)
896 resp
= Signal
.like(master
.r
.resp
)
897 addr_counter
= Signal(master_align
)
901 # Slave address counter
902 self
.comb
+= addr_counter
[slave_align
:].eq(counter
)
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
))
911 slave
.ar
.addr
.eq(Cat(addr_counter
, master
.ar
.addr
[master_align
:])),
912 master
.r
.resp
.eq(resp
),
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
))
924 NextValue(counter
, 0),
925 NextValue(resp
, RESP_OKAY
),
931 slave
.ar
.valid
.eq(1),
933 NextState("RESPOND-SLAVE")
936 fsm
.act("RESPOND-SLAVE",
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
)
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
949 NextValue(counter
, counter
+ 1),
954 fsm
.act("RESPOND-MASTER",
955 master
.r
.valid
.eq(1),
962 class AXILiteDownConverter(Module
):
963 def __init__(self
, master
, slave
):
964 self
.submodules
.write
= _AXILiteDownConverterWrite(master
, slave
)
965 self
.submodules
.read
= _AXILiteDownConverterRead(master
, slave
)
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)
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
))
985 self
.comb
+= master
.connect(slave
, omit
={"addr", "strb", "data"})
989 slave
.aw
.addr
[slave_align
:].eq(master
.aw
.addr
[slave_align
:]),
990 slave
.ar
.addr
[slave_align
:].eq(master
.ar
.addr
[slave_align
:]),
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
1001 slave
.w
.strb
[strb_from
:strb_to
].eq(master
.w
.strb
),
1002 slave
.w
.data
[data_from
:data_to
].eq(master
.w
.data
),
1005 master
.r
.data
.eq(slave
.r
.data
[data_from
:data_to
]),
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
))
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
]),
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
]),
1022 self
.comb
+= Case(wr_word
, wr_cases
)
1023 self
.comb
+= Case(rd_word
, rd_cases
)
1025 class AXILiteConverter(Module
):
1026 """AXILite data width converter"""
1027 def __init__(self
, master
, slave
):
1028 self
.master
= master
1033 dw_from
= len(master
.r
.data
)
1034 dw_to
= len(slave
.r
.data
)
1036 self
.submodules
+= AXILiteDownConverter(master
, slave
)
1037 elif dw_from
< dw_to
:
1038 self
.submodules
+= AXILiteUpConverter(master
, slave
)
1040 self
.comb
+= master
.connect(slave
)
1042 # AXILite Timeout ----------------------------------------------------------------------------------
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()
1053 self
.comb
+= self
.error
.eq(wr_error | rd_error
)
1055 wr_timer
= WaitTimer(int(cycles
))
1056 rd_timer
= WaitTimer(int(cycles
))
1057 self
.submodules
+= wr_timer
, rd_timer
1059 def channel_fsm(timer
, wait_cond
, error
, response
):
1060 fsm
= FSM(reset_state
="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
,
1067 NextState("RESPOND")
1070 fsm
.act("RESPOND", *response
)
1073 self
.submodules
.wr_fsm
= channel_fsm(
1075 wait_cond
= (master
.aw
.valid
& ~master
.aw
.ready
) |
(master
.w
.valid
& ~master
.w
.ready
),
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
,
1087 self
.submodules
.rd_fsm
= channel_fsm(
1089 wait_cond
= master
.ar
.valid
& ~master
.ar
.ready
,
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
,
1101 # AXILite Interconnect -----------------------------------------------------------------------------
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
1112 full
.eq(counter
== max_requests
- 1),
1113 empty
.eq(counter
== 0),
1114 stall
.eq(request
& full
),
1118 If(request
& response
,
1120 ).Elif(request
& ~full
,
1121 counter
.eq(counter
+ 1)
1122 ).Elif(response
& ~empty
,
1123 counter
.eq(counter
- 1)
1127 class AXILiteInterconnectPointToPoint(Module
):
1128 def __init__(self
, master
, slave
):
1129 self
.comb
+= master
.connect(slave
)
1131 class AXILiteArbiter(Module
):
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.
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
)
1142 def get_sig(interface
, channel
, name
):
1143 return getattr(getattr(interface
, channel
), name
)
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
])
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
)
1160 self
.comb
+= dest
.eq(source
& (rr
.grant
== i
))
1162 self
.comb
+= dest
.eq(source
)
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
)
1170 # switch to next request only if there are no responses pending
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
),
1176 # connect bus requests to round-robin selectors
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
])),
1182 class AXILiteDecoder(Module
):
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.
1190 __doc__
= """AXI Lite decoder
1192 Decode master access to particular slave based on its decoder function.
1195 """.format(slaves
=_doc_slaves
)
1197 def __init__(self
, master
, slaves
, register
=False):
1198 # TODO: unused register argument
1199 addr_shift
= log2_int(master
.data_width
//8)
1202 "write": {"aw", "w", "b"},
1203 "read": {"ar", "r"},
1205 # reverse mapping: directions[channel] -> "write"/"read"
1206 directions
= {ch
: d
for d
, chs
in channels
.items() for ch
in chs
}
1208 def new_slave_sel():
1209 return {"write": Signal(len(slaves
)), "read": Signal(len(slaves
))}
1211 slave_sel_dec
= new_slave_sel()
1212 slave_sel_reg
= new_slave_sel()
1213 slave_sel
= new_slave_sel()
1215 # we need to hold the slave selected until all responses come back
1216 # TODO: we could reuse arbiter counters
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
),
1225 self
.submodules
+= locks
.values()
1227 def get_sig(interface
, channel
, name
):
1228 return getattr(getattr(interface
, channel
), name
)
1232 # decode slave addresses
1233 for i
, (decoder
, bus
) in enumerate(slaves
):
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
:])),
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
])
1247 final
.eq(slave_sel_reg
[ch
])
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
)
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
)
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
))
1273 class AXILiteInterconnectShared(Module
):
1274 __doc__
= """AXI Lite shared interconnect
1277 """.format(slaves
=AXILiteDecoder
._doc
_slaves
)
1279 def __init__(self
, masters
, slaves
, register
=False, timeout_cycles
=1e6
):
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
)
1287 class AXILiteCrossbar(Module
):
1288 __doc__
= """AXI Lite crossbar
1290 MxN crossbar for M masters and N slaves.
1293 """.format(slaves
=AXILiteDecoder
._doc
_slaves
)
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
)