958061a9bbee575280e12e9c9845285a6affbde9
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
501 _data
= Signal(axi_lite
.data_width
)
502 _r_addr
= Signal(axi_lite
.address_width
)
503 _w_addr
= Signal(axi_lite
.address_width
)
504 _last_ar_aw_n
= Signal()
505 self
.comb
+= _r_addr
.eq(axi_lite
.ar
.addr
- base_address
)
506 self
.comb
+= _w_addr
.eq(axi_lite
.aw
.addr
- base_address
)
508 self
.submodules
.fsm
= fsm
= FSM(reset_state
="IDLE")
510 If(axi_lite
.ar
.valid
& axi_lite
.aw
.valid
,
511 # If last access was a read, do a write
513 NextValue(_last_ar_aw_n
, 0),
514 NextState("DO-WRITE")
515 # If last access was a write, do a read
517 NextValue(_last_ar_aw_n
, 1),
520 ).Elif(axi_lite
.ar
.valid
,
521 NextValue(_last_ar_aw_n
, 1),
523 ).Elif(axi_lite
.aw
.valid
,
524 NextValue(_last_ar_aw_n
, 0),
525 NextState("DO-WRITE")
531 wishbone
.adr
.eq(_r_addr
[wishbone_adr_shift
:]),
532 wishbone
.sel
.eq(2**len(wishbone
.sel
) - 1),
534 axi_lite
.ar
.ready
.eq(1),
535 NextValue(_data
, wishbone
.dat_r
),
536 NextState("SEND-READ-RESPONSE")
539 fsm
.act("SEND-READ-RESPONSE",
540 axi_lite
.r
.valid
.eq(1),
541 axi_lite
.r
.resp
.eq(RESP_OKAY
),
542 axi_lite
.r
.data
.eq(_data
),
548 wishbone
.stb
.eq(axi_lite
.w
.valid
),
549 wishbone
.cyc
.eq(axi_lite
.w
.valid
),
551 wishbone
.adr
.eq(_w_addr
[wishbone_adr_shift
:]),
552 wishbone
.sel
.eq(axi_lite
.w
.strb
),
553 wishbone
.dat_w
.eq(axi_lite
.w
.data
),
555 axi_lite
.aw
.ready
.eq(1),
556 axi_lite
.w
.ready
.eq(1),
557 NextState("SEND-WRITE-RESPONSE")
560 fsm
.act("SEND-WRITE-RESPONSE",
561 axi_lite
.b
.valid
.eq(1),
562 axi_lite
.b
.resp
.eq(RESP_OKAY
),
568 # AXI to Wishbone ----------------------------------------------------------------------------------
570 class AXI2Wishbone(Module
):
571 def __init__(self
, axi
, wishbone
, base_address
=0x00000000):
572 axi_lite
= AXILiteInterface(axi
.data_width
, axi
.address_width
)
573 axi2axi_lite
= AXI2AXILite(axi
, axi_lite
)
574 axi_lite2wishbone
= AXILite2Wishbone(axi_lite
, wishbone
, base_address
)
575 self
.submodules
+= axi2axi_lite
, axi_lite2wishbone
577 # Wishbone to AXILite ------------------------------------------------------------------------------
579 class Wishbone2AXILite(Module
):
580 def __init__(self
, wishbone
, axi_lite
, base_address
=0x00000000):
581 wishbone_adr_shift
= log2_int(axi_lite
.data_width
//8)
582 assert axi_lite
.data_width
== len(wishbone
.dat_r
)
583 assert axi_lite
.address_width
== len(wishbone
.adr
) + wishbone_adr_shift
586 _data_done
= Signal()
587 _addr
= Signal(len(wishbone
.adr
))
588 self
.comb
+= _addr
.eq(wishbone
.adr
- base_address
//4)
590 self
.submodules
.fsm
= fsm
= FSM(reset_state
="IDLE")
592 NextValue(_cmd_done
, 0),
593 NextValue(_data_done
, 0),
594 If(wishbone
.stb
& wishbone
.cyc
,
604 axi_lite
.aw
.valid
.eq(~_cmd_done
),
605 axi_lite
.aw
.addr
[wishbone_adr_shift
:].eq(_addr
),
606 If(axi_lite
.aw
.valid
& axi_lite
.aw
.ready
,
607 NextValue(_cmd_done
, 1)
610 axi_lite
.w
.valid
.eq(~_data_done
),
611 axi_lite
.w
.data
.eq(wishbone
.dat_w
),
612 axi_lite
.w
.strb
.eq(wishbone
.sel
),
613 If(axi_lite
.w
.valid
& axi_lite
.w
.ready
,
614 NextValue(_data_done
, 1),
617 axi_lite
.b
.ready
.eq(_cmd_done
& _data_done
),
618 If(axi_lite
.b
.valid
& axi_lite
.b
.ready
,
619 If(axi_lite
.b
.resp
== RESP_OKAY
,
629 axi_lite
.ar
.valid
.eq(~_cmd_done
),
630 axi_lite
.ar
.addr
[wishbone_adr_shift
:].eq(_addr
),
631 If(axi_lite
.ar
.valid
& axi_lite
.ar
.ready
,
632 NextValue(_cmd_done
, 1)
635 axi_lite
.r
.ready
.eq(_cmd_done
),
636 If(axi_lite
.r
.valid
& axi_lite
.r
.ready
,
637 If(axi_lite
.r
.resp
== RESP_OKAY
,
638 wishbone
.dat_r
.eq(axi_lite
.r
.data
),
652 # AXILite to CSR -----------------------------------------------------------------------------------
654 def axi_lite_to_simple(axi_lite
, port_adr
, port_dat_r
, port_dat_w
=None, port_we
=None):
655 """Connection of AXILite to simple bus with 1-cycle latency, such as CSR bus or Memory port"""
656 bus_data_width
= axi_lite
.data_width
657 adr_shift
= log2_int(bus_data_width
//8)
660 last_was_read
= Signal()
663 if port_dat_w
is not None:
664 comb
.append(port_dat_w
.eq(axi_lite
.w
.data
))
665 if port_we
is not None:
667 for i
in range(bus_data_width
//8):
668 comb
.append(port_we
[i
].eq(axi_lite
.w
.valid
& axi_lite
.w
.ready
& axi_lite
.w
.strb
[i
]))
670 comb
.append(port_we
.eq(axi_lite
.w
.valid
& axi_lite
.w
.ready
& (axi_lite
.w
.strb
!= 0)))
673 fsm
.act("START-TRANSACTION",
674 # If the last access was a read, do a write, and vice versa
675 If(axi_lite
.aw
.valid
& axi_lite
.ar
.valid
,
676 do_write
.eq(last_was_read
),
677 do_read
.eq(~last_was_read
),
679 do_write
.eq(axi_lite
.aw
.valid
),
680 do_read
.eq(axi_lite
.ar
.valid
),
682 # Start reading/writing immediately not to waste a cycle
684 port_adr
.eq(axi_lite
.aw
.addr
[adr_shift
:]),
686 axi_lite
.aw
.ready
.eq(1),
687 axi_lite
.w
.ready
.eq(1),
688 NextState("SEND-WRITE-RESPONSE")
691 port_adr
.eq(axi_lite
.ar
.addr
[adr_shift
:]),
692 axi_lite
.ar
.ready
.eq(1),
693 NextState("SEND-READ-RESPONSE"),
696 fsm
.act("SEND-READ-RESPONSE",
697 NextValue(last_was_read
, 1),
698 # As long as we have correct address port.dat_r will be valid
699 port_adr
.eq(axi_lite
.ar
.addr
[adr_shift
:]),
700 axi_lite
.r
.data
.eq(port_dat_r
),
701 axi_lite
.r
.resp
.eq(RESP_OKAY
),
702 axi_lite
.r
.valid
.eq(1),
704 NextState("START-TRANSACTION")
707 fsm
.act("SEND-WRITE-RESPONSE",
708 NextValue(last_was_read
, 0),
709 axi_lite
.b
.valid
.eq(1),
710 axi_lite
.b
.resp
.eq(RESP_OKAY
),
712 NextState("START-TRANSACTION")
717 class AXILite2CSR(Module
):
718 def __init__(self
, axi_lite
=None, bus_csr
=None):
720 axi_lite
= AXILiteInterface()
722 bus_csr
= csr_bus
.Interface()
724 self
.axi_lite
= axi_lite
727 fsm
, comb
= axi_lite_to_simple(self
.axi_lite
,
728 port_adr
=self
.csr
.adr
, port_dat_r
=self
.csr
.dat_r
,
729 port_dat_w
=self
.csr
.dat_w
, port_we
=self
.csr
.we
)
730 self
.submodules
.fsm
= fsm
733 # AXILite SRAM -------------------------------------------------------------------------------------
735 class AXILiteSRAM(Module
):
736 def __init__(self
, mem_or_size
, read_only
=None, init
=None, bus
=None):
738 bus
= AXILiteInterface()
741 bus_data_width
= len(self
.bus
.r
.data
)
742 if isinstance(mem_or_size
, Memory
):
743 assert(mem_or_size
.width
<= bus_data_width
)
744 self
.mem
= mem_or_size
746 self
.mem
= Memory(bus_data_width
, mem_or_size
//(bus_data_width
//8), init
=init
)
748 if read_only
is None:
749 if hasattr(self
.mem
, "bus_read_only"):
750 read_only
= self
.mem
.bus_read_only
757 port
= self
.mem
.get_port(write_capable
=not read_only
, we_granularity
=8,
758 mode
=READ_FIRST
if read_only
else WRITE_FIRST
)
759 self
.specials
+= self
.mem
, port
761 # Generate write enable signal
763 self
.comb
+= port
.dat_w
.eq(self
.bus
.w
.data
),
764 self
.comb
+= [port
.we
[i
].eq(self
.bus
.w
.valid
& self
.bus
.w
.ready
& self
.bus
.w
.strb
[i
])
765 for i
in range(bus_data_width
//8)]
768 fsm
, comb
= axi_lite_to_simple(self
.bus
,
769 port_adr
=port
.adr
, port_dat_r
=port
.dat_r
,
770 port_dat_w
=port
.dat_w
if not read_only
else None,
771 port_we
=port
.we
if not read_only
else None)
772 self
.submodules
.fsm
= fsm
775 # AXILite Data Width Converter ---------------------------------------------------------------------
777 class _AXILiteDownConverterWrite(Module
):
778 def __init__(self
, master
, slave
):
779 assert isinstance(master
, AXILiteInterface
) and isinstance(slave
, AXILiteInterface
)
780 dw_from
= len(master
.w
.data
)
781 dw_to
= len(slave
.w
.data
)
782 ratio
= dw_from
//dw_to
783 master_align
= log2_int(master
.data_width
//8)
784 slave_align
= log2_int(slave
.data_width
//8)
787 counter
= Signal(max=ratio
)
790 resp
= Signal
.like(master
.b
.resp
)
791 addr_counter
= Signal(master_align
)
795 # Slave address counter
796 self
.comb
+= addr_counter
[slave_align
:].eq(counter
)
800 slave
.aw
.addr
.eq(Cat(addr_counter
, master
.aw
.addr
[master_align
:])),
801 Case(counter
, {i
: slave
.w
.data
.eq(master
.w
.data
[i
*dw_to
:]) for i
in range(ratio
)}),
802 Case(counter
, {i
: slave
.w
.strb
.eq(master
.w
.strb
[i
*dw_to
//8:]) for i
in range(ratio
)}),
803 master
.b
.resp
.eq(resp
),
807 fsm
= FSM(reset_state
="IDLE")
808 fsm
= ResetInserter()(fsm
)
809 self
.submodules
.fsm
= fsm
810 # Reset the converter state if master breaks a request, we can do that as
811 # aw.valid and w.valid are kept high in CONVERT and RESPOND-SLAVE, and
812 # acknowledged only when moving to RESPOND-MASTER, and then b.valid is 1
813 self
.comb
+= fsm
.reset
.eq(~
((master
.aw
.valid | master
.w
.valid
) | master
.b
.valid
))
816 NextValue(counter
, 0),
817 NextValue(resp
, RESP_OKAY
),
818 If(master
.aw
.valid
& master
.w
.valid
,
823 skip
.eq(slave
.w
.strb
== 0),
824 slave
.aw
.valid
.eq(~skip
& ~aw_ready
),
825 slave
.w
.valid
.eq(~skip
& ~w_ready
),
827 NextValue(aw_ready
, 1)
830 NextValue(w_ready
, 1)
832 # When skipping, we just increment the counter
834 NextValue(counter
, counter
+ 1),
835 # Corner-case: when the last word is being skipped, we must send the response
836 If(counter
== (ratio
- 1),
837 master
.aw
.ready
.eq(1),
838 master
.w
.ready
.eq(1),
839 NextState("RESPOND-MASTER")
841 # Write current word and wait for write response
842 ).Elif((slave
.aw
.ready | aw_ready
) & (slave
.w
.ready | w_ready
),
843 NextState("RESPOND-SLAVE")
846 fsm
.act("RESPOND-SLAVE",
847 NextValue(aw_ready
, 0),
848 NextValue(w_ready
, 0),
851 # Errors are sticky, so the first one is always sent
852 If((resp
== RESP_OKAY
) & (slave
.b
.resp
!= RESP_OKAY
),
853 NextValue(resp
, slave
.b
.resp
)
855 If(counter
== (ratio
- 1),
856 master
.aw
.ready
.eq(1),
857 master
.w
.ready
.eq(1),
858 NextState("RESPOND-MASTER")
860 NextValue(counter
, counter
+ 1),
865 fsm
.act("RESPOND-MASTER",
866 NextValue(aw_ready
, 0),
867 NextValue(w_ready
, 0),
868 master
.b
.valid
.eq(1),
874 class _AXILiteDownConverterRead(Module
):
875 def __init__(self
, master
, slave
):
876 assert isinstance(master
, AXILiteInterface
) and isinstance(slave
, AXILiteInterface
)
877 dw_from
= len(master
.r
.data
)
878 dw_to
= len(slave
.r
.data
)
879 ratio
= dw_from
//dw_to
880 master_align
= log2_int(master
.data_width
//8)
881 slave_align
= log2_int(slave
.data_width
//8)
884 counter
= Signal(max=ratio
)
885 resp
= Signal
.like(master
.r
.resp
)
886 addr_counter
= Signal(master_align
)
890 # Slave address counter
891 self
.comb
+= addr_counter
[slave_align
:].eq(counter
)
894 # shift the data word
895 r_data
= Signal(dw_from
, reset_less
=True)
896 self
.sync
+= If(slave
.r
.ready
, r_data
.eq(master
.r
.data
))
897 self
.comb
+= master
.r
.data
.eq(Cat(r_data
[dw_to
:], slave
.r
.data
))
900 slave
.ar
.addr
.eq(Cat(addr_counter
, master
.ar
.addr
[master_align
:])),
901 master
.r
.resp
.eq(resp
),
905 fsm
= FSM(reset_state
="IDLE")
906 fsm
= ResetInserter()(fsm
)
907 self
.submodules
.fsm
= fsm
908 # Reset the converter state if master breaks a request, we can do that as
909 # ar.valid is high in CONVERT and RESPOND-SLAVE, and r.valid in RESPOND-MASTER
910 self
.comb
+= fsm
.reset
.eq(~
(master
.ar
.valid | master
.r
.valid
))
913 NextValue(counter
, 0),
914 NextValue(resp
, RESP_OKAY
),
920 slave
.ar
.valid
.eq(1),
922 NextState("RESPOND-SLAVE")
925 fsm
.act("RESPOND-SLAVE",
927 # Errors are sticky, so the first one is always sent
928 If((resp
== RESP_OKAY
) & (slave
.r
.resp
!= RESP_OKAY
),
929 NextValue(resp
, slave
.r
.resp
)
931 # On last word acknowledge ar and hold slave.r.valid until we get master.r.ready
932 If(counter
== (ratio
- 1),
933 master
.ar
.ready
.eq(1),
934 NextState("RESPOND-MASTER")
935 # Acknowledge the response and continue conversion
938 NextValue(counter
, counter
+ 1),
943 fsm
.act("RESPOND-MASTER",
944 master
.r
.valid
.eq(1),
951 class AXILiteDownConverter(Module
):
952 def __init__(self
, master
, slave
):
953 self
.submodules
.write
= _AXILiteDownConverterWrite(master
, slave
)
954 self
.submodules
.read
= _AXILiteDownConverterRead(master
, slave
)
956 class AXILiteUpConverter(Module
):
957 # TODO: we could try joining multiple master accesses into single slave access
958 # would reuqire checking if address changes and a way to flush on single access
959 def __init__(self
, master
, slave
):
960 assert isinstance(master
, AXILiteInterface
) and isinstance(slave
, AXILiteInterface
)
961 dw_from
= len(master
.r
.data
)
962 dw_to
= len(slave
.r
.data
)
963 ratio
= dw_to
//dw_from
964 master_align
= log2_int(master
.data_width
//8)
965 slave_align
= log2_int(slave
.data_width
//8)
967 wr_word
= Signal(log2_int(ratio
))
968 rd_word
= Signal(log2_int(ratio
))
969 wr_word_r
= Signal(log2_int(ratio
))
970 rd_word_r
= Signal(log2_int(ratio
))
974 self
.comb
+= master
.connect(slave
, omit
={"addr", "strb", "data"})
978 slave
.aw
.addr
[slave_align
:].eq(master
.aw
.addr
[slave_align
:]),
979 slave
.ar
.addr
[slave_align
:].eq(master
.ar
.addr
[slave_align
:]),
983 wr_cases
, rd_cases
= {}, {}
984 for i
in range(ratio
):
985 strb_from
= i
* dw_from
//8
986 strb_to
= (i
+1) * dw_from
//8
987 data_from
= i
* dw_from
988 data_to
= (i
+1) * dw_from
990 slave
.w
.strb
[strb_from
:strb_to
].eq(master
.w
.strb
),
991 slave
.w
.data
[data_from
:data_to
].eq(master
.w
.data
),
994 master
.r
.data
.eq(slave
.r
.data
[data_from
:data_to
]),
997 # Switch current word based on the last valid master address
998 self
.sync
+= If(master
.aw
.valid
, wr_word_r
.eq(wr_word
))
999 self
.sync
+= If(master
.ar
.valid
, rd_word_r
.eq(rd_word
))
1001 Case(master
.aw
.valid
, {
1002 0: wr_word
.eq(wr_word_r
),
1003 1: wr_word
.eq(master
.aw
.addr
[master_align
:slave_align
]),
1005 Case(master
.ar
.valid
, {
1006 0: rd_word
.eq(rd_word_r
),
1007 1: rd_word
.eq(master
.ar
.addr
[master_align
:slave_align
]),
1011 self
.comb
+= Case(wr_word
, wr_cases
)
1012 self
.comb
+= Case(rd_word
, rd_cases
)
1014 class AXILiteConverter(Module
):
1015 """AXILite data width converter"""
1016 def __init__(self
, master
, slave
):
1017 self
.master
= master
1022 dw_from
= len(master
.r
.data
)
1023 dw_to
= len(slave
.r
.data
)
1025 self
.submodules
+= AXILiteDownConverter(master
, slave
)
1026 elif dw_from
< dw_to
:
1027 self
.submodules
+= AXILiteUpConverter(master
, slave
)
1029 self
.comb
+= master
.connect(slave
)
1031 # AXILite Timeout ----------------------------------------------------------------------------------
1033 class AXILiteTimeout(Module
):
1034 """Protect master against slave timeouts (master _has_ to respond correctly)"""
1035 def __init__(self
, master
, cycles
):
1036 self
.error
= Signal()
1042 self
.comb
+= self
.error
.eq(wr_error | rd_error
)
1044 wr_timer
= WaitTimer(int(cycles
))
1045 rd_timer
= WaitTimer(int(cycles
))
1046 self
.submodules
+= wr_timer
, rd_timer
1048 def channel_fsm(timer
, wait_cond
, error
, response
):
1049 fsm
= FSM(reset_state
="WAIT")
1051 timer
.wait
.eq(wait_cond
),
1052 # done is updated in `sync`, so we must make sure that `ready` has not been issued
1053 # by slave during that single cycle, by checking `timer.wait`
1054 If(timer
.done
& timer
.wait
,
1056 NextState("RESPOND")
1059 fsm
.act("RESPOND", *response
)
1062 self
.submodules
.wr_fsm
= channel_fsm(
1064 wait_cond
= (master
.aw
.valid
& ~master
.aw
.ready
) |
(master
.w
.valid
& ~master
.w
.ready
),
1067 master
.aw
.ready
.eq(master
.aw
.valid
),
1068 master
.w
.ready
.eq(master
.w
.valid
),
1069 master
.b
.valid
.eq(~master
.aw
.valid
& ~master
.w
.valid
),
1070 master
.b
.resp
.eq(RESP_SLVERR
),
1071 If(master
.b
.valid
& master
.b
.ready
,
1076 self
.submodules
.rd_fsm
= channel_fsm(
1078 wait_cond
= master
.ar
.valid
& ~master
.ar
.ready
,
1081 master
.ar
.ready
.eq(master
.ar
.valid
),
1082 master
.r
.valid
.eq(~master
.ar
.valid
),
1083 master
.r
.resp
.eq(RESP_SLVERR
),
1084 master
.r
.data
.eq(2**len(master
.r
.data
) - 1),
1085 If(master
.r
.valid
& master
.r
.ready
,
1090 # AXILite Interconnect -----------------------------------------------------------------------------
1092 class _AXILiteRequestCounter(Module
):
1093 def __init__(self
, request
, response
, max_requests
=256):
1094 self
.counter
= counter
= Signal(max=max_requests
)
1095 self
.full
= full
= Signal()
1096 self
.empty
= empty
= Signal()
1097 self
.stall
= stall
= Signal()
1098 self
.ready
= self
.empty
1101 full
.eq(counter
== max_requests
- 1),
1102 empty
.eq(counter
== 0),
1103 stall
.eq(request
& full
),
1107 If(request
& response
,
1109 ).Elif(request
& ~full
,
1110 counter
.eq(counter
+ 1)
1111 ).Elif(response
& ~empty
,
1112 counter
.eq(counter
- 1)
1116 class AXILiteInterconnectPointToPoint(Module
):
1117 def __init__(self
, master
, slave
):
1118 self
.comb
+= master
.connect(slave
)
1120 class AXILiteArbiter(Module
):
1123 Arbitrate between master interfaces and connect one to the target.
1124 New master will not be selected until all requests have been responded to.
1125 Arbitration for write and read channels is done separately.
1127 def __init__(self
, masters
, target
):
1128 self
.submodules
.rr_write
= roundrobin
.RoundRobin(len(masters
), roundrobin
.SP_CE
)
1129 self
.submodules
.rr_read
= roundrobin
.RoundRobin(len(masters
), roundrobin
.SP_CE
)
1131 def get_sig(interface
, channel
, name
):
1132 return getattr(getattr(interface
, channel
), name
)
1134 # mux master->slave signals
1135 for channel
, name
, direction
in target
.layout_flat():
1136 rr
= self
.rr_write
if channel
in ["aw", "w", "b"] else self
.rr_read
1137 if direction
== DIR_M_TO_S
:
1138 choices
= Array(get_sig(m
, channel
, name
) for m
in masters
)
1139 self
.comb
+= get_sig(target
, channel
, name
).eq(choices
[rr
.grant
])
1141 # connect slave->master signals
1142 for channel
, name
, direction
in target
.layout_flat():
1143 rr
= self
.rr_write
if channel
in ["aw", "w", "b"] else self
.rr_read
1144 if direction
== DIR_S_TO_M
:
1145 source
= get_sig(target
, channel
, name
)
1146 for i
, m
in enumerate(masters
):
1147 dest
= get_sig(m
, channel
, name
)
1149 self
.comb
+= dest
.eq(source
& (rr
.grant
== i
))
1151 self
.comb
+= dest
.eq(source
)
1153 # allow to change rr.grant only after all requests from a master have been responded to
1154 self
.submodules
.wr_lock
= wr_lock
= _AXILiteRequestCounter(
1155 request
=target
.aw
.valid
& target
.aw
.ready
, response
=target
.b
.valid
& target
.b
.ready
)
1156 self
.submodules
.rd_lock
= rd_lock
= _AXILiteRequestCounter(
1157 request
=target
.ar
.valid
& target
.ar
.ready
, response
=target
.r
.valid
& target
.r
.ready
)
1159 # switch to next request only if there are no responses pending
1161 self
.rr_write
.ce
.eq(~
(target
.aw
.valid | target
.w
.valid | target
.b
.valid
) & wr_lock
.ready
),
1162 self
.rr_read
.ce
.eq(~
(target
.ar
.valid | target
.r
.valid
) & rd_lock
.ready
),
1165 # connect bus requests to round-robin selectors
1167 self
.rr_write
.request
.eq(Cat(*[m
.aw
.valid | m
.w
.valid | m
.b
.valid
for m
in masters
])),
1168 self
.rr_read
.request
.eq(Cat(*[m
.ar
.valid | m
.r
.valid
for m
in masters
])),
1171 class AXILiteDecoder(Module
):
1173 slaves: [(decoder, slave), ...]
1174 List of slaves with address decoders, where `decoder` is a function:
1175 decoder(Signal(address_width - log2(data_width//8))) -> Signal(1)
1176 that returns 1 when the slave is selected and 0 otherwise.
1179 __doc__
= """AXI Lite decoder
1181 Decode master access to particular slave based on its decoder function.
1184 """.format(slaves
=_doc_slaves
)
1186 def __init__(self
, master
, slaves
, register
=False):
1187 # TODO: unused register argument
1188 addr_shift
= log2_int(master
.data_width
//8)
1191 "write": {"aw", "w", "b"},
1192 "read": {"ar", "r"},
1194 # reverse mapping: directions[channel] -> "write"/"read"
1195 directions
= {ch
: d
for d
, chs
in channels
.items() for ch
in chs
}
1197 def new_slave_sel():
1198 return {"write": Signal(len(slaves
)), "read": Signal(len(slaves
))}
1200 slave_sel_dec
= new_slave_sel()
1201 slave_sel_reg
= new_slave_sel()
1202 slave_sel
= new_slave_sel()
1204 # we need to hold the slave selected until all responses come back
1205 # TODO: we could reuse arbiter counters
1207 "write": _AXILiteRequestCounter(
1208 request
=master
.aw
.valid
& master
.aw
.ready
,
1209 response
=master
.b
.valid
& master
.b
.ready
),
1210 "read": _AXILiteRequestCounter(
1211 request
=master
.ar
.valid
& master
.ar
.ready
,
1212 response
=master
.r
.valid
& master
.r
.ready
),
1214 self
.submodules
+= locks
.values()
1216 def get_sig(interface
, channel
, name
):
1217 return getattr(getattr(interface
, channel
), name
)
1221 # decode slave addresses
1222 for i
, (decoder
, bus
) in enumerate(slaves
):
1224 slave_sel_dec
["write"][i
].eq(decoder(master
.aw
.addr
[addr_shift
:])),
1225 slave_sel_dec
["read"][i
].eq(decoder(master
.ar
.addr
[addr_shift
:])),
1228 # change the current selection only when we've got all responses
1229 for channel
in locks
.keys():
1230 self
.sync
+= If(locks
[channel
].ready
, slave_sel_reg
[channel
].eq(slave_sel_dec
[channel
]))
1231 # we have to cut the delaying select
1232 for ch
, final
in slave_sel
.items():
1233 self
.comb
+= If(locks
[ch
].ready
,
1234 final
.eq(slave_sel_dec
[ch
])
1236 final
.eq(slave_sel_reg
[ch
])
1239 # connect master->slaves signals except valid/ready
1240 for i
, (_
, slave
) in enumerate(slaves
):
1241 for channel
, name
, direction
in master
.layout_flat():
1242 if direction
== DIR_M_TO_S
:
1243 src
= get_sig(master
, channel
, name
)
1244 dst
= get_sig(slave
, channel
, name
)
1245 # mask master control signals depending on slave selection
1246 if name
in ["valid", "ready"]:
1247 src
= src
& slave_sel
[directions
[channel
]][i
]
1248 self
.comb
+= dst
.eq(src
)
1250 # connect slave->master signals masking not selected slaves
1251 for channel
, name
, direction
in master
.layout_flat():
1252 if direction
== DIR_S_TO_M
:
1253 dst
= get_sig(master
, channel
, name
)
1255 for i
, (_
, slave
) in enumerate(slaves
):
1256 src
= get_sig(slave
, channel
, name
)
1257 # mask depending on channel
1258 mask
= Replicate(slave_sel
[directions
[channel
]][i
], len(dst
))
1259 masked
.append(src
& mask
)
1260 self
.comb
+= dst
.eq(reduce(or_
, masked
))
1262 class AXILiteInterconnectShared(Module
):
1263 __doc__
= """AXI Lite shared interconnect
1266 """.format(slaves
=AXILiteDecoder
._doc
_slaves
)
1268 def __init__(self
, masters
, slaves
, register
=False, timeout_cycles
=1e6
):
1270 shared
= AXILiteInterface()
1271 self
.submodules
.arbiter
= AXILiteArbiter(masters
, shared
)
1272 self
.submodules
.decoder
= AXILiteDecoder(shared
, slaves
)
1273 if timeout_cycles
is not None:
1274 self
.submodules
.timeout
= AXILiteTimeout(shared
, timeout_cycles
)
1276 class AXILiteCrossbar(Module
):
1277 __doc__
= """AXI Lite crossbar
1279 MxN crossbar for M masters and N slaves.
1282 """.format(slaves
=AXILiteDecoder
._doc
_slaves
)
1284 def __init__(self
, masters
, slaves
, register
=False, timeout_cycles
=1e6
):
1285 matches
, busses
= zip(*slaves
)
1286 access_m_s
= [[AXILiteInterface() for j
in slaves
] for i
in masters
] # a[master][slave]
1287 access_s_m
= list(zip(*access_m_s
)) # a[slave][master]
1288 # decode each master into its access row
1289 for slaves
, master
in zip(access_m_s
, masters
):
1290 slaves
= list(zip(matches
, slaves
))
1291 self
.submodules
+= AXILiteDecoder(master
, slaves
, register
)
1292 # arbitrate each access column onto its slave
1293 for masters
, bus
in zip(access_s_m
, busses
):
1294 self
.submodules
+= AXILiteArbiter(masters
, bus
)