ec25bbaeae405f666353cd392ac46085167049bf
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 # Wishbone to AXI ----------------------------------------------------------------------------------
654 class Wishbone2AXI(Module
):
655 def __init__(self
, wishbone
, axi
, base_address
=0x00000000):
656 axi_lite
= AXILiteInterface(axi
.data_width
, axi
.address_width
)
657 wishbone2axi_lite
= Wishbone2AXILite(wishbone
, axi_lite
, base_address
)
658 axi_lite2axi
= AXILite2AXI(axi_lite
, axi
)
659 self
.submodules
+= wishbone2axi_lite
, axi_lite2axi
661 # AXILite to CSR -----------------------------------------------------------------------------------
663 def axi_lite_to_simple(axi_lite
, port_adr
, port_dat_r
, port_dat_w
=None, port_we
=None):
664 """Connection of AXILite to simple bus with 1-cycle latency, such as CSR bus or Memory port"""
665 bus_data_width
= axi_lite
.data_width
666 adr_shift
= log2_int(bus_data_width
//8)
669 last_was_read
= Signal()
672 if port_dat_w
is not None:
673 comb
.append(port_dat_w
.eq(axi_lite
.w
.data
))
674 if port_we
is not None:
676 for i
in range(bus_data_width
//8):
677 comb
.append(port_we
[i
].eq(axi_lite
.w
.valid
& axi_lite
.w
.ready
& axi_lite
.w
.strb
[i
]))
679 comb
.append(port_we
.eq(axi_lite
.w
.valid
& axi_lite
.w
.ready
& (axi_lite
.w
.strb
!= 0)))
682 fsm
.act("START-TRANSACTION",
683 # If the last access was a read, do a write, and vice versa
684 If(axi_lite
.aw
.valid
& axi_lite
.ar
.valid
,
685 do_write
.eq(last_was_read
),
686 do_read
.eq(~last_was_read
),
688 do_write
.eq(axi_lite
.aw
.valid
),
689 do_read
.eq(axi_lite
.ar
.valid
),
691 # Start reading/writing immediately not to waste a cycle
693 port_adr
.eq(axi_lite
.aw
.addr
[adr_shift
:]),
695 axi_lite
.aw
.ready
.eq(1),
696 axi_lite
.w
.ready
.eq(1),
697 NextState("SEND-WRITE-RESPONSE")
700 port_adr
.eq(axi_lite
.ar
.addr
[adr_shift
:]),
701 axi_lite
.ar
.ready
.eq(1),
702 NextState("SEND-READ-RESPONSE"),
705 fsm
.act("SEND-READ-RESPONSE",
706 NextValue(last_was_read
, 1),
707 # As long as we have correct address port.dat_r will be valid
708 port_adr
.eq(axi_lite
.ar
.addr
[adr_shift
:]),
709 axi_lite
.r
.data
.eq(port_dat_r
),
710 axi_lite
.r
.resp
.eq(RESP_OKAY
),
711 axi_lite
.r
.valid
.eq(1),
713 NextState("START-TRANSACTION")
716 fsm
.act("SEND-WRITE-RESPONSE",
717 NextValue(last_was_read
, 0),
718 axi_lite
.b
.valid
.eq(1),
719 axi_lite
.b
.resp
.eq(RESP_OKAY
),
721 NextState("START-TRANSACTION")
726 class AXILite2CSR(Module
):
727 def __init__(self
, axi_lite
=None, bus_csr
=None):
729 axi_lite
= AXILiteInterface()
731 bus_csr
= csr_bus
.Interface()
733 self
.axi_lite
= axi_lite
736 fsm
, comb
= axi_lite_to_simple(self
.axi_lite
,
737 port_adr
=self
.csr
.adr
, port_dat_r
=self
.csr
.dat_r
,
738 port_dat_w
=self
.csr
.dat_w
, port_we
=self
.csr
.we
)
739 self
.submodules
.fsm
= fsm
742 # AXILite SRAM -------------------------------------------------------------------------------------
744 class AXILiteSRAM(Module
):
745 def __init__(self
, mem_or_size
, read_only
=None, init
=None, bus
=None):
747 bus
= AXILiteInterface()
750 bus_data_width
= len(self
.bus
.r
.data
)
751 if isinstance(mem_or_size
, Memory
):
752 assert(mem_or_size
.width
<= bus_data_width
)
753 self
.mem
= mem_or_size
755 self
.mem
= Memory(bus_data_width
, mem_or_size
//(bus_data_width
//8), init
=init
)
757 if read_only
is None:
758 if hasattr(self
.mem
, "bus_read_only"):
759 read_only
= self
.mem
.bus_read_only
766 port
= self
.mem
.get_port(write_capable
=not read_only
, we_granularity
=8,
767 mode
=READ_FIRST
if read_only
else WRITE_FIRST
)
768 self
.specials
+= self
.mem
, port
770 # Generate write enable signal
772 self
.comb
+= port
.dat_w
.eq(self
.bus
.w
.data
),
773 self
.comb
+= [port
.we
[i
].eq(self
.bus
.w
.valid
& self
.bus
.w
.ready
& self
.bus
.w
.strb
[i
])
774 for i
in range(bus_data_width
//8)]
777 fsm
, comb
= axi_lite_to_simple(self
.bus
,
778 port_adr
=port
.adr
, port_dat_r
=port
.dat_r
,
779 port_dat_w
=port
.dat_w
if not read_only
else None,
780 port_we
=port
.we
if not read_only
else None)
781 self
.submodules
.fsm
= fsm
784 # AXILite Data Width Converter ---------------------------------------------------------------------
786 class _AXILiteDownConverterWrite(Module
):
787 def __init__(self
, master
, slave
):
788 assert isinstance(master
, AXILiteInterface
) and isinstance(slave
, AXILiteInterface
)
789 dw_from
= len(master
.w
.data
)
790 dw_to
= len(slave
.w
.data
)
791 ratio
= dw_from
//dw_to
792 master_align
= log2_int(master
.data_width
//8)
793 slave_align
= log2_int(slave
.data_width
//8)
796 counter
= Signal(max=ratio
)
799 resp
= Signal
.like(master
.b
.resp
)
800 addr_counter
= Signal(master_align
)
804 # Slave address counter
805 self
.comb
+= addr_counter
[slave_align
:].eq(counter
)
809 slave
.aw
.addr
.eq(Cat(addr_counter
, master
.aw
.addr
[master_align
:])),
810 Case(counter
, {i
: slave
.w
.data
.eq(master
.w
.data
[i
*dw_to
:]) for i
in range(ratio
)}),
811 Case(counter
, {i
: slave
.w
.strb
.eq(master
.w
.strb
[i
*dw_to
//8:]) for i
in range(ratio
)}),
812 master
.b
.resp
.eq(resp
),
816 fsm
= FSM(reset_state
="IDLE")
817 fsm
= ResetInserter()(fsm
)
818 self
.submodules
.fsm
= fsm
819 # Reset the converter state if master breaks a request, we can do that as
820 # aw.valid and w.valid are kept high in CONVERT and RESPOND-SLAVE, and
821 # acknowledged only when moving to RESPOND-MASTER, and then b.valid is 1
822 self
.comb
+= fsm
.reset
.eq(~
((master
.aw
.valid | master
.w
.valid
) | master
.b
.valid
))
825 NextValue(counter
, 0),
826 NextValue(resp
, RESP_OKAY
),
827 If(master
.aw
.valid
& master
.w
.valid
,
832 skip
.eq(slave
.w
.strb
== 0),
833 slave
.aw
.valid
.eq(~skip
& ~aw_ready
),
834 slave
.w
.valid
.eq(~skip
& ~w_ready
),
836 NextValue(aw_ready
, 1)
839 NextValue(w_ready
, 1)
841 # When skipping, we just increment the counter
843 NextValue(counter
, counter
+ 1),
844 # Corner-case: when the last word is being skipped, we must send the response
845 If(counter
== (ratio
- 1),
846 master
.aw
.ready
.eq(1),
847 master
.w
.ready
.eq(1),
848 NextState("RESPOND-MASTER")
850 # Write current word and wait for write response
851 ).Elif((slave
.aw
.ready | aw_ready
) & (slave
.w
.ready | w_ready
),
852 NextState("RESPOND-SLAVE")
855 fsm
.act("RESPOND-SLAVE",
856 NextValue(aw_ready
, 0),
857 NextValue(w_ready
, 0),
860 # Errors are sticky, so the first one is always sent
861 If((resp
== RESP_OKAY
) & (slave
.b
.resp
!= RESP_OKAY
),
862 NextValue(resp
, slave
.b
.resp
)
864 If(counter
== (ratio
- 1),
865 master
.aw
.ready
.eq(1),
866 master
.w
.ready
.eq(1),
867 NextState("RESPOND-MASTER")
869 NextValue(counter
, counter
+ 1),
874 fsm
.act("RESPOND-MASTER",
875 NextValue(aw_ready
, 0),
876 NextValue(w_ready
, 0),
877 master
.b
.valid
.eq(1),
883 class _AXILiteDownConverterRead(Module
):
884 def __init__(self
, master
, slave
):
885 assert isinstance(master
, AXILiteInterface
) and isinstance(slave
, AXILiteInterface
)
886 dw_from
= len(master
.r
.data
)
887 dw_to
= len(slave
.r
.data
)
888 ratio
= dw_from
//dw_to
889 master_align
= log2_int(master
.data_width
//8)
890 slave_align
= log2_int(slave
.data_width
//8)
893 counter
= Signal(max=ratio
)
894 resp
= Signal
.like(master
.r
.resp
)
895 addr_counter
= Signal(master_align
)
899 # Slave address counter
900 self
.comb
+= addr_counter
[slave_align
:].eq(counter
)
903 # shift the data word
904 r_data
= Signal(dw_from
, reset_less
=True)
905 self
.sync
+= If(slave
.r
.ready
, r_data
.eq(master
.r
.data
))
906 self
.comb
+= master
.r
.data
.eq(Cat(r_data
[dw_to
:], slave
.r
.data
))
909 slave
.ar
.addr
.eq(Cat(addr_counter
, master
.ar
.addr
[master_align
:])),
910 master
.r
.resp
.eq(resp
),
914 fsm
= FSM(reset_state
="IDLE")
915 fsm
= ResetInserter()(fsm
)
916 self
.submodules
.fsm
= fsm
917 # Reset the converter state if master breaks a request, we can do that as
918 # ar.valid is high in CONVERT and RESPOND-SLAVE, and r.valid in RESPOND-MASTER
919 self
.comb
+= fsm
.reset
.eq(~
(master
.ar
.valid | master
.r
.valid
))
922 NextValue(counter
, 0),
923 NextValue(resp
, RESP_OKAY
),
929 slave
.ar
.valid
.eq(1),
931 NextState("RESPOND-SLAVE")
934 fsm
.act("RESPOND-SLAVE",
936 # Errors are sticky, so the first one is always sent
937 If((resp
== RESP_OKAY
) & (slave
.r
.resp
!= RESP_OKAY
),
938 NextValue(resp
, slave
.r
.resp
)
940 # On last word acknowledge ar and hold slave.r.valid until we get master.r.ready
941 If(counter
== (ratio
- 1),
942 master
.ar
.ready
.eq(1),
943 NextState("RESPOND-MASTER")
944 # Acknowledge the response and continue conversion
947 NextValue(counter
, counter
+ 1),
952 fsm
.act("RESPOND-MASTER",
953 master
.r
.valid
.eq(1),
960 class AXILiteDownConverter(Module
):
961 def __init__(self
, master
, slave
):
962 self
.submodules
.write
= _AXILiteDownConverterWrite(master
, slave
)
963 self
.submodules
.read
= _AXILiteDownConverterRead(master
, slave
)
965 class AXILiteUpConverter(Module
):
966 # TODO: we could try joining multiple master accesses into single slave access
967 # would reuqire checking if address changes and a way to flush on single access
968 def __init__(self
, master
, slave
):
969 assert isinstance(master
, AXILiteInterface
) and isinstance(slave
, AXILiteInterface
)
970 dw_from
= len(master
.r
.data
)
971 dw_to
= len(slave
.r
.data
)
972 ratio
= dw_to
//dw_from
973 master_align
= log2_int(master
.data_width
//8)
974 slave_align
= log2_int(slave
.data_width
//8)
976 wr_word
= Signal(log2_int(ratio
))
977 rd_word
= Signal(log2_int(ratio
))
978 wr_word_r
= Signal(log2_int(ratio
))
979 rd_word_r
= Signal(log2_int(ratio
))
983 self
.comb
+= master
.connect(slave
, omit
={"addr", "strb", "data"})
987 slave
.aw
.addr
[slave_align
:].eq(master
.aw
.addr
[slave_align
:]),
988 slave
.ar
.addr
[slave_align
:].eq(master
.ar
.addr
[slave_align
:]),
992 wr_cases
, rd_cases
= {}, {}
993 for i
in range(ratio
):
994 strb_from
= i
* dw_from
//8
995 strb_to
= (i
+1) * dw_from
//8
996 data_from
= i
* dw_from
997 data_to
= (i
+1) * dw_from
999 slave
.w
.strb
[strb_from
:strb_to
].eq(master
.w
.strb
),
1000 slave
.w
.data
[data_from
:data_to
].eq(master
.w
.data
),
1003 master
.r
.data
.eq(slave
.r
.data
[data_from
:data_to
]),
1006 # Switch current word based on the last valid master address
1007 self
.sync
+= If(master
.aw
.valid
, wr_word_r
.eq(wr_word
))
1008 self
.sync
+= If(master
.ar
.valid
, rd_word_r
.eq(rd_word
))
1010 Case(master
.aw
.valid
, {
1011 0: wr_word
.eq(wr_word_r
),
1012 1: wr_word
.eq(master
.aw
.addr
[master_align
:slave_align
]),
1014 Case(master
.ar
.valid
, {
1015 0: rd_word
.eq(rd_word_r
),
1016 1: rd_word
.eq(master
.ar
.addr
[master_align
:slave_align
]),
1020 self
.comb
+= Case(wr_word
, wr_cases
)
1021 self
.comb
+= Case(rd_word
, rd_cases
)
1023 class AXILiteConverter(Module
):
1024 """AXILite data width converter"""
1025 def __init__(self
, master
, slave
):
1026 self
.master
= master
1031 dw_from
= len(master
.r
.data
)
1032 dw_to
= len(slave
.r
.data
)
1034 self
.submodules
+= AXILiteDownConverter(master
, slave
)
1035 elif dw_from
< dw_to
:
1036 self
.submodules
+= AXILiteUpConverter(master
, slave
)
1038 self
.comb
+= master
.connect(slave
)
1040 # AXILite Timeout ----------------------------------------------------------------------------------
1042 class AXILiteTimeout(Module
):
1043 """Protect master against slave timeouts (master _has_ to respond correctly)"""
1044 def __init__(self
, master
, cycles
):
1045 self
.error
= Signal()
1051 self
.comb
+= self
.error
.eq(wr_error | rd_error
)
1053 wr_timer
= WaitTimer(int(cycles
))
1054 rd_timer
= WaitTimer(int(cycles
))
1055 self
.submodules
+= wr_timer
, rd_timer
1057 def channel_fsm(timer
, wait_cond
, error
, response
):
1058 fsm
= FSM(reset_state
="WAIT")
1060 timer
.wait
.eq(wait_cond
),
1061 # done is updated in `sync`, so we must make sure that `ready` has not been issued
1062 # by slave during that single cycle, by checking `timer.wait`
1063 If(timer
.done
& timer
.wait
,
1065 NextState("RESPOND")
1068 fsm
.act("RESPOND", *response
)
1071 self
.submodules
.wr_fsm
= channel_fsm(
1073 wait_cond
= (master
.aw
.valid
& ~master
.aw
.ready
) |
(master
.w
.valid
& ~master
.w
.ready
),
1076 master
.aw
.ready
.eq(master
.aw
.valid
),
1077 master
.w
.ready
.eq(master
.w
.valid
),
1078 master
.b
.valid
.eq(~master
.aw
.valid
& ~master
.w
.valid
),
1079 master
.b
.resp
.eq(RESP_SLVERR
),
1080 If(master
.b
.valid
& master
.b
.ready
,
1085 self
.submodules
.rd_fsm
= channel_fsm(
1087 wait_cond
= master
.ar
.valid
& ~master
.ar
.ready
,
1090 master
.ar
.ready
.eq(master
.ar
.valid
),
1091 master
.r
.valid
.eq(~master
.ar
.valid
),
1092 master
.r
.resp
.eq(RESP_SLVERR
),
1093 master
.r
.data
.eq(2**len(master
.r
.data
) - 1),
1094 If(master
.r
.valid
& master
.r
.ready
,
1099 # AXILite Interconnect -----------------------------------------------------------------------------
1101 class _AXILiteRequestCounter(Module
):
1102 def __init__(self
, request
, response
, max_requests
=256):
1103 self
.counter
= counter
= Signal(max=max_requests
)
1104 self
.full
= full
= Signal()
1105 self
.empty
= empty
= Signal()
1106 self
.stall
= stall
= Signal()
1107 self
.ready
= self
.empty
1110 full
.eq(counter
== max_requests
- 1),
1111 empty
.eq(counter
== 0),
1112 stall
.eq(request
& full
),
1116 If(request
& response
,
1118 ).Elif(request
& ~full
,
1119 counter
.eq(counter
+ 1)
1120 ).Elif(response
& ~empty
,
1121 counter
.eq(counter
- 1)
1125 class AXILiteInterconnectPointToPoint(Module
):
1126 def __init__(self
, master
, slave
):
1127 self
.comb
+= master
.connect(slave
)
1129 class AXILiteArbiter(Module
):
1132 Arbitrate between master interfaces and connect one to the target.
1133 New master will not be selected until all requests have been responded to.
1134 Arbitration for write and read channels is done separately.
1136 def __init__(self
, masters
, target
):
1137 self
.submodules
.rr_write
= roundrobin
.RoundRobin(len(masters
), roundrobin
.SP_CE
)
1138 self
.submodules
.rr_read
= roundrobin
.RoundRobin(len(masters
), roundrobin
.SP_CE
)
1140 def get_sig(interface
, channel
, name
):
1141 return getattr(getattr(interface
, channel
), name
)
1143 # mux master->slave signals
1144 for channel
, name
, direction
in target
.layout_flat():
1145 rr
= self
.rr_write
if channel
in ["aw", "w", "b"] else self
.rr_read
1146 if direction
== DIR_M_TO_S
:
1147 choices
= Array(get_sig(m
, channel
, name
) for m
in masters
)
1148 self
.comb
+= get_sig(target
, channel
, name
).eq(choices
[rr
.grant
])
1150 # connect slave->master signals
1151 for channel
, name
, direction
in target
.layout_flat():
1152 rr
= self
.rr_write
if channel
in ["aw", "w", "b"] else self
.rr_read
1153 if direction
== DIR_S_TO_M
:
1154 source
= get_sig(target
, channel
, name
)
1155 for i
, m
in enumerate(masters
):
1156 dest
= get_sig(m
, channel
, name
)
1158 self
.comb
+= dest
.eq(source
& (rr
.grant
== i
))
1160 self
.comb
+= dest
.eq(source
)
1162 # allow to change rr.grant only after all requests from a master have been responded to
1163 self
.submodules
.wr_lock
= wr_lock
= _AXILiteRequestCounter(
1164 request
=target
.aw
.valid
& target
.aw
.ready
, response
=target
.b
.valid
& target
.b
.ready
)
1165 self
.submodules
.rd_lock
= rd_lock
= _AXILiteRequestCounter(
1166 request
=target
.ar
.valid
& target
.ar
.ready
, response
=target
.r
.valid
& target
.r
.ready
)
1168 # switch to next request only if there are no responses pending
1170 self
.rr_write
.ce
.eq(~
(target
.aw
.valid | target
.w
.valid | target
.b
.valid
) & wr_lock
.ready
),
1171 self
.rr_read
.ce
.eq(~
(target
.ar
.valid | target
.r
.valid
) & rd_lock
.ready
),
1174 # connect bus requests to round-robin selectors
1176 self
.rr_write
.request
.eq(Cat(*[m
.aw
.valid | m
.w
.valid | m
.b
.valid
for m
in masters
])),
1177 self
.rr_read
.request
.eq(Cat(*[m
.ar
.valid | m
.r
.valid
for m
in masters
])),
1180 class AXILiteDecoder(Module
):
1182 slaves: [(decoder, slave), ...]
1183 List of slaves with address decoders, where `decoder` is a function:
1184 decoder(Signal(address_width - log2(data_width//8))) -> Signal(1)
1185 that returns 1 when the slave is selected and 0 otherwise.
1188 __doc__
= """AXI Lite decoder
1190 Decode master access to particular slave based on its decoder function.
1193 """.format(slaves
=_doc_slaves
)
1195 def __init__(self
, master
, slaves
, register
=False):
1196 # TODO: unused register argument
1197 addr_shift
= log2_int(master
.data_width
//8)
1200 "write": {"aw", "w", "b"},
1201 "read": {"ar", "r"},
1203 # reverse mapping: directions[channel] -> "write"/"read"
1204 directions
= {ch
: d
for d
, chs
in channels
.items() for ch
in chs
}
1206 def new_slave_sel():
1207 return {"write": Signal(len(slaves
)), "read": Signal(len(slaves
))}
1209 slave_sel_dec
= new_slave_sel()
1210 slave_sel_reg
= new_slave_sel()
1211 slave_sel
= new_slave_sel()
1213 # we need to hold the slave selected until all responses come back
1214 # TODO: we could reuse arbiter counters
1216 "write": _AXILiteRequestCounter(
1217 request
=master
.aw
.valid
& master
.aw
.ready
,
1218 response
=master
.b
.valid
& master
.b
.ready
),
1219 "read": _AXILiteRequestCounter(
1220 request
=master
.ar
.valid
& master
.ar
.ready
,
1221 response
=master
.r
.valid
& master
.r
.ready
),
1223 self
.submodules
+= locks
.values()
1225 def get_sig(interface
, channel
, name
):
1226 return getattr(getattr(interface
, channel
), name
)
1230 # decode slave addresses
1231 for i
, (decoder
, bus
) in enumerate(slaves
):
1233 slave_sel_dec
["write"][i
].eq(decoder(master
.aw
.addr
[addr_shift
:])),
1234 slave_sel_dec
["read"][i
].eq(decoder(master
.ar
.addr
[addr_shift
:])),
1237 # change the current selection only when we've got all responses
1238 for channel
in locks
.keys():
1239 self
.sync
+= If(locks
[channel
].ready
, slave_sel_reg
[channel
].eq(slave_sel_dec
[channel
]))
1240 # we have to cut the delaying select
1241 for ch
, final
in slave_sel
.items():
1242 self
.comb
+= If(locks
[ch
].ready
,
1243 final
.eq(slave_sel_dec
[ch
])
1245 final
.eq(slave_sel_reg
[ch
])
1248 # connect master->slaves signals except valid/ready
1249 for i
, (_
, slave
) in enumerate(slaves
):
1250 for channel
, name
, direction
in master
.layout_flat():
1251 if direction
== DIR_M_TO_S
:
1252 src
= get_sig(master
, channel
, name
)
1253 dst
= get_sig(slave
, channel
, name
)
1254 # mask master control signals depending on slave selection
1255 if name
in ["valid", "ready"]:
1256 src
= src
& slave_sel
[directions
[channel
]][i
]
1257 self
.comb
+= dst
.eq(src
)
1259 # connect slave->master signals masking not selected slaves
1260 for channel
, name
, direction
in master
.layout_flat():
1261 if direction
== DIR_S_TO_M
:
1262 dst
= get_sig(master
, channel
, name
)
1264 for i
, (_
, slave
) in enumerate(slaves
):
1265 src
= get_sig(slave
, channel
, name
)
1266 # mask depending on channel
1267 mask
= Replicate(slave_sel
[directions
[channel
]][i
], len(dst
))
1268 masked
.append(src
& mask
)
1269 self
.comb
+= dst
.eq(reduce(or_
, masked
))
1271 class AXILiteInterconnectShared(Module
):
1272 __doc__
= """AXI Lite shared interconnect
1275 """.format(slaves
=AXILiteDecoder
._doc
_slaves
)
1277 def __init__(self
, masters
, slaves
, register
=False, timeout_cycles
=1e6
):
1279 shared
= AXILiteInterface()
1280 self
.submodules
.arbiter
= AXILiteArbiter(masters
, shared
)
1281 self
.submodules
.decoder
= AXILiteDecoder(shared
, slaves
)
1282 if timeout_cycles
is not None:
1283 self
.submodules
.timeout
= AXILiteTimeout(shared
, timeout_cycles
)
1285 class AXILiteCrossbar(Module
):
1286 __doc__
= """AXI Lite crossbar
1288 MxN crossbar for M masters and N slaves.
1291 """.format(slaves
=AXILiteDecoder
._doc
_slaves
)
1293 def __init__(self
, masters
, slaves
, register
=False, timeout_cycles
=1e6
):
1294 matches
, busses
= zip(*slaves
)
1295 access_m_s
= [[AXILiteInterface() for j
in slaves
] for i
in masters
] # a[master][slave]
1296 access_s_m
= list(zip(*access_m_s
)) # a[slave][master]
1297 # decode each master into its access row
1298 for slaves
, master
in zip(access_m_s
, masters
):
1299 slaves
= list(zip(matches
, slaves
))
1300 self
.submodules
+= AXILiteDecoder(master
, slaves
, register
)
1301 # arbitrate each access column onto its slave
1302 for masters
, bus
in zip(access_s_m
, busses
):
1303 self
.submodules
+= AXILiteArbiter(masters
, bus
)