a1fd90b6ed4200dc9ce7faea90231901749c04f1
[litex.git] / litex / soc / interconnect / axi.py
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>
3 # License: BSD
4
5 """AXI4 Full/Lite support for LiteX"""
6
7 from migen import *
8 from migen.genlib import roundrobin
9 from migen.genlib.misc import split, displacer, chooser, WaitTimer
10
11 from litex.soc.interconnect import stream
12 from litex.build.generic_platform import *
13
14 from litex.soc.interconnect import csr_bus
15
16 # AXI Definition -----------------------------------------------------------------------------------
17
18 BURST_FIXED = 0b00
19 BURST_INCR = 0b01
20 BURST_WRAP = 0b10
21 BURST_RESERVED = 0b11
22
23 RESP_OKAY = 0b00
24 RESP_EXOKAY = 0b01
25 RESP_SLVERR = 0b10
26 RESP_DECERR = 0b11
27
28 def ax_description(address_width, id_width):
29 return [
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)
34 ("lock", 2), # *
35 ("prot", 3), # *
36 ("cache", 4), # *
37 ("qos", 4), # *
38 ("id", id_width)
39 ]
40 # * present for interconnect with others cores but not used by LiteX.
41
42 def w_description(data_width, id_width):
43 return [
44 ("data", data_width),
45 ("strb", data_width//8),
46 ("id", id_width)
47 ]
48
49 def b_description(id_width):
50 return [
51 ("resp", 2),
52 ("id", id_width)
53 ]
54
55 def r_description(data_width, id_width):
56 return [
57 ("resp", 2),
58 ("data", data_width),
59 ("id", id_width)
60 ]
61
62 def _connect_axi(master, slave, keep=None, omit=None):
63 channel_modes = {
64 "aw": "master",
65 "w" : "master",
66 "b" : "slave",
67 "ar": "master",
68 "r" : "slave",
69 }
70 r = []
71 for channel, mode in channel_modes.items():
72 if mode == "master":
73 m, s = getattr(master, channel), getattr(slave, channel)
74 else:
75 s, m = getattr(master, channel), getattr(slave, channel)
76 r.extend(m.connect(s, keep=keep, omit=omit))
77 return r
78
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]
84 return direction
85 for ch in ["aw", "w", "b", "ar", "r"]:
86 channel = getattr(axi, ch)
87 for group in channel.layout:
88 if len(group) == 3:
89 name, _, direction = group
90 yield ch, name, get_dir(ch, direction)
91 else:
92 _, subgroups = group
93 for subgroup in subgroups:
94 name, _, direction = subgroup
95 yield ch, name, get_dir(ch, direction)
96
97 class AXIInterface:
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
103
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))
109
110 def connect(self, slave, **kwargs):
111 return _connect_axi(self, slave, **kwargs)
112
113 def layout_flat(self):
114 return list(_axi_layout_flat(self))
115
116 # AXI Lite Definition ------------------------------------------------------------------------------
117
118 def ax_lite_description(address_width):
119 return [("addr", address_width)]
120
121 def w_lite_description(data_width):
122 return [
123 ("data", data_width),
124 ("strb", data_width//8)
125 ]
126
127 def b_lite_description():
128 return [("resp", 2)]
129
130 def r_lite_description(data_width):
131 return [
132 ("resp", 2),
133 ("data", data_width)
134 ]
135
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
141
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)
147
148 def get_ios(self, bus_name="wb"):
149 subsignals = []
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)]
156 return ios
157
158 def connect_to_pads(self, pads, mode="master"):
159 assert mode in ["slave", "master"]
160 r = []
161 def swap_mode(mode): return "master" if mode == "slave" else "slave"
162 channel_modes = {
163 "aw": mode,
164 "w" : mode,
165 "b" : swap_mode(mode),
166 "ar": mode,
167 "r" : swap_mode(mode),
168 }
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)
173 if mode == "master":
174 r.append(pad.eq(sig))
175 else:
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)
180 if mode == "master":
181 r.append(sig.eq(pad))
182 else:
183 r.append(pad.eq(sig))
184 return r
185
186 def connect(self, slave, **kwargs):
187 return _connect_axi(self, slave, **kwargs)
188
189 def layout_flat(self):
190 return list(_axi_layout_flat(self))
191
192 def write(self, addr, data, strb=None):
193 if strb is None:
194 strb = 2**len(self.w.strb) - 1
195 # aw + w
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)
201 yield
202 while not (yield self.aw.ready):
203 yield
204 yield self.aw.valid.eq(0)
205 yield self.aw.addr.eq(0)
206 while not (yield self.w.ready):
207 yield
208 yield self.w.valid.eq(0)
209 yield self.w.strb.eq(0)
210 # b
211 yield self.b.ready.eq(1)
212 while not (yield self.b.valid):
213 yield
214 resp = (yield self.b.resp)
215 yield self.b.ready.eq(0)
216 return resp
217
218 def read(self, addr):
219 # ar
220 yield self.ar.valid.eq(1)
221 yield self.ar.addr.eq(addr)
222 yield
223 while not (yield self.ar.ready):
224 yield
225 yield self.ar.valid.eq(0)
226 # r
227 yield self.r.ready.eq(1)
228 while not (yield self.r.valid):
229 yield
230 data = (yield self.r.data)
231 resp = (yield self.r.resp)
232 yield self.r.ready.eq(0)
233 return (data, resp)
234
235 # AXI Stream Definition ----------------------------------------------------------------------------
236
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)]
242 if self.user_width:
243 axi_layout += [("user", user_width)]
244 stream.Endpoint.__init__(self, axi_layout)
245
246 def get_ios(self, bus_name="axi"):
247 subsignals = [
248 Subsignal("tvalid", Pins(1)),
249 Subsignal("tlast", Pins(1)),
250 Subsignal("tready", Pins(1)),
251 Subsignal("tdata", Pins(self.data_width)),
252 ]
253 if self.user_width:
254 subsignals += [Subsignal("tuser", Pins(self.user_width))]
255 ios = [(bus_name , 0) + tuple(subsignals)]
256 return ios
257
258 def connect_to_pads(self, pads, mode="master"):
259 assert mode in ["slave", "master"]
260 r = []
261 if mode == "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))
266 if self.user_width:
267 r.append(pads.tuser.eq(self.user))
268 if mode == "slave":
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))
273 if self.user_width:
274 r.append(self.user.eq(pads.tuser))
275 return r
276
277 # AXI Bursts to Beats ------------------------------------------------------------------------------
278
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
282
283 # # #
284
285 beat_count = Signal(8)
286 beat_size = Signal(8 + 4)
287 beat_offset = Signal(8 + 4)
288 beat_wrap = Signal(8 + 4)
289
290 # compute parameters
291 self.comb += beat_size.eq(1 << ax_burst.size)
292 self.comb += beat_wrap.eq(ax_burst.len << ax_burst.size)
293
294 # combinatorial logic
295 self.comb += [
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),
301 If(ax_beat.ready,
302 If(ax_beat.last,
303 ax_burst.ready.eq(1)
304 )
305 )
306 ]
307
308 # synchronous logic
309 self.sync += [
310 If(ax_beat.valid & ax_beat.ready,
311 If(ax_beat.last,
312 beat_count.eq(0),
313 beat_offset.eq(0)
314 ).Else(
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)
319 )
320 ),
321 If((ax_burst.burst == BURST_WRAP) & (BURST_WRAP in capabilities),
322 If(beat_offset == beat_wrap,
323 beat_offset.eq(0)
324 )
325 )
326 )
327 ]
328
329
330 # AXI to AXI Lite ----------------------------------------------------------------------------------
331
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
339
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
346
347 _data = Signal(axi.data_width)
348 _cmd_done = Signal()
349 _last_ar_aw_n = Signal()
350
351 self.submodules.fsm = fsm = FSM(reset_state="IDLE")
352 fsm.act("IDLE",
353 NextValue(_cmd_done, 0),
354 If(axi.ar.valid & axi.aw.valid,
355 # If last access was a read, do a write
356 If(_last_ar_aw_n,
357 axi.aw.connect(ax_burst),
358 NextValue(_last_ar_aw_n, 0),
359 NextState("WRITE")
360 # If last access was a write, do a read
361 ).Else(
362 axi.ar.connect(ax_burst),
363 NextValue(_last_ar_aw_n, 1),
364 NextState("READ"),
365 )
366 ).Elif(axi.ar.valid,
367 axi.ar.connect(ax_burst),
368 NextValue(_last_ar_aw_n, 1),
369 NextState("READ"),
370 ).Elif(axi.aw.valid,
371 axi.aw.connect(ax_burst),
372 NextValue(_last_ar_aw_n, 0),
373 NextState("WRITE")
374 )
375 )
376 fsm.act("READ",
377 # cmd
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,
383 ax_beat.ready.eq(0),
384 NextValue(_cmd_done, 1)
385 )
386 ),
387 # data
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),
394 # exit
395 If(axi.r.valid & axi.r.last & axi.r.ready,
396 ax_beat.ready.eq(1),
397 NextState("IDLE")
398 )
399 )
400 # always accept write responses
401 self.comb += axi_lite.b.ready.eq(1)
402 fsm.act("WRITE",
403 # cmd
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,
409 ax_beat.ready.eq(0),
410 NextValue(_cmd_done, 1)
411 )
412 ),
413 # data
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),
418 # exit
419 If(axi.w.valid & axi.w.last & axi.w.ready,
420 NextState("WRITE-RESP")
421 )
422 )
423 fsm.act("WRITE-RESP",
424 axi.b.valid.eq(1),
425 axi.b.resp.eq(RESP_OKAY),
426 axi.b.id.eq(ax_beat.id),
427 If(axi.b.ready,
428 ax_beat.ready.eq(1),
429 NextState("IDLE")
430 )
431 )
432
433 # AXI Lite to Wishbone -----------------------------------------------------------------------------
434
435 class AXILite2Wishbone(Module):
436 def __init__(self, axi_lite, wishbone, base_address=0x00000000):
437 wishbone_adr_shift = log2_int(axi_lite.data_width//8)
438 assert axi_lite.data_width == len(wishbone.dat_r)
439 assert axi_lite.address_width == len(wishbone.adr) + wishbone_adr_shift
440
441 _data = Signal(axi_lite.data_width)
442 _r_addr = Signal(axi_lite.address_width)
443 _w_addr = Signal(axi_lite.address_width)
444 _last_ar_aw_n = Signal()
445 self.comb += _r_addr.eq(axi_lite.ar.addr - base_address)
446 self.comb += _w_addr.eq(axi_lite.aw.addr - base_address)
447
448 self.submodules.fsm = fsm = FSM(reset_state="IDLE")
449 fsm.act("IDLE",
450 If(axi_lite.ar.valid & axi_lite.aw.valid,
451 # If last access was a read, do a write
452 If(_last_ar_aw_n,
453 NextValue(_last_ar_aw_n, 0),
454 NextState("DO-WRITE")
455 # If last access was a write, do a read
456 ).Else(
457 NextValue(_last_ar_aw_n, 1),
458 NextState("DO-READ")
459 )
460 ).Elif(axi_lite.ar.valid,
461 NextValue(_last_ar_aw_n, 1),
462 NextState("DO-READ")
463 ).Elif(axi_lite.aw.valid,
464 NextValue(_last_ar_aw_n, 0),
465 NextState("DO-WRITE")
466 )
467 )
468 fsm.act("DO-READ",
469 wishbone.stb.eq(1),
470 wishbone.cyc.eq(1),
471 wishbone.adr.eq(_r_addr[wishbone_adr_shift:]),
472 wishbone.sel.eq(2**len(wishbone.sel) - 1),
473 If(wishbone.ack,
474 axi_lite.ar.ready.eq(1),
475 NextValue(_data, wishbone.dat_r),
476 NextState("SEND-READ-RESPONSE")
477 )
478 )
479 fsm.act("SEND-READ-RESPONSE",
480 axi_lite.r.valid.eq(1),
481 axi_lite.r.resp.eq(RESP_OKAY),
482 axi_lite.r.data.eq(_data),
483 If(axi_lite.r.ready,
484 NextState("IDLE")
485 )
486 )
487 fsm.act("DO-WRITE",
488 wishbone.stb.eq(axi_lite.w.valid),
489 wishbone.cyc.eq(axi_lite.w.valid),
490 wishbone.we.eq(1),
491 wishbone.adr.eq(_w_addr[wishbone_adr_shift:]),
492 wishbone.sel.eq(axi_lite.w.strb),
493 wishbone.dat_w.eq(axi_lite.w.data),
494 If(wishbone.ack,
495 axi_lite.aw.ready.eq(1),
496 axi_lite.w.ready.eq(1),
497 NextState("SEND-WRITE-RESPONSE")
498 )
499 )
500 fsm.act("SEND-WRITE-RESPONSE",
501 axi_lite.b.valid.eq(1),
502 axi_lite.b.resp.eq(RESP_OKAY),
503 If(axi_lite.b.ready,
504 NextState("IDLE")
505 )
506 )
507
508 # AXI to Wishbone ----------------------------------------------------------------------------------
509
510 class AXI2Wishbone(Module):
511 def __init__(self, axi, wishbone, base_address=0x00000000):
512 axi_lite = AXILiteInterface(axi.data_width, axi.address_width)
513 axi2axi_lite = AXI2AXILite(axi, axi_lite)
514 axi_lite2wishbone = AXILite2Wishbone(axi_lite, wishbone, base_address)
515 self.submodules += axi2axi_lite, axi_lite2wishbone
516
517 # Wishbone to AXILite ------------------------------------------------------------------------------
518
519 class Wishbone2AXILite(Module):
520 def __init__(self, wishbone, axi_lite, base_address=0x00000000):
521 wishbone_adr_shift = log2_int(axi_lite.data_width//8)
522 assert axi_lite.data_width == len(wishbone.dat_r)
523 assert axi_lite.address_width == len(wishbone.adr) + wishbone_adr_shift
524
525 _cmd_done = Signal()
526 _data_done = Signal()
527 _addr = Signal(len(wishbone.adr))
528 self.comb += _addr.eq(wishbone.adr - base_address//4)
529
530 self.submodules.fsm = fsm = FSM(reset_state="IDLE")
531 fsm.act("IDLE",
532 NextValue(_cmd_done, 0),
533 NextValue(_data_done, 0),
534 If(wishbone.stb & wishbone.cyc,
535 If(wishbone.we,
536 NextState("WRITE")
537 ).Else(
538 NextState("READ")
539 )
540 )
541 )
542 fsm.act("WRITE",
543 # cmd
544 axi_lite.aw.valid.eq(~_cmd_done),
545 axi_lite.aw.addr[wishbone_adr_shift:].eq(_addr),
546 If(axi_lite.aw.valid & axi_lite.aw.ready,
547 NextValue(_cmd_done, 1)
548 ),
549 # data
550 axi_lite.w.valid.eq(~_data_done),
551 axi_lite.w.data.eq(wishbone.dat_w),
552 axi_lite.w.strb.eq(wishbone.sel),
553 If(axi_lite.w.valid & axi_lite.w.ready,
554 NextValue(_data_done, 1),
555 ),
556 # resp
557 axi_lite.b.ready.eq(_cmd_done & _data_done),
558 If(axi_lite.b.valid & axi_lite.b.ready,
559 If(axi_lite.b.resp == RESP_OKAY,
560 wishbone.ack.eq(1),
561 NextState("IDLE")
562 ).Else(
563 NextState("ERROR")
564 )
565 )
566 )
567 fsm.act("READ",
568 # cmd
569 axi_lite.ar.valid.eq(~_cmd_done),
570 axi_lite.ar.addr[wishbone_adr_shift:].eq(_addr),
571 If(axi_lite.ar.valid & axi_lite.ar.ready,
572 NextValue(_cmd_done, 1)
573 ),
574 # data & resp
575 axi_lite.r.ready.eq(_cmd_done),
576 If(axi_lite.r.valid & axi_lite.r.ready,
577 If(axi_lite.r.resp == RESP_OKAY,
578 wishbone.dat_r.eq(axi_lite.r.data),
579 wishbone.ack.eq(1),
580 NextState("IDLE"),
581 ).Else(
582 NextState("ERROR")
583 )
584 )
585 )
586 fsm.act("ERROR",
587 wishbone.ack.eq(1),
588 wishbone.err.eq(1),
589 NextState("IDLE")
590 )
591
592 # AXILite to CSR -----------------------------------------------------------------------------------
593
594 def axi_lite_to_simple(axi_lite, port_adr, port_dat_r, port_dat_w=None, port_we=None):
595 """Connection of AXILite to simple bus with 1-cycle latency, such as CSR bus or Memory port"""
596 bus_data_width = axi_lite.data_width
597 adr_shift = log2_int(bus_data_width//8)
598 do_read = Signal()
599 do_write = Signal()
600 last_was_read = Signal()
601
602 comb = []
603 if port_dat_w is not None:
604 comb.append(port_dat_w.eq(axi_lite.w.data))
605 if port_we is not None:
606 if len(port_we) > 1:
607 for i in range(bus_data_width//8):
608 comb.append(port_we[i].eq(axi_lite.w.valid & axi_lite.w.ready & axi_lite.w.strb[i]))
609 else:
610 comb.append(port_we.eq(axi_lite.w.valid & axi_lite.w.ready & (axi_lite.w.strb != 0)))
611
612 fsm = FSM()
613 fsm.act("START-TRANSACTION",
614 # If the last access was a read, do a write, and vice versa
615 If(axi_lite.aw.valid & axi_lite.ar.valid,
616 do_write.eq(last_was_read),
617 do_read.eq(~last_was_read),
618 ).Else(
619 do_write.eq(axi_lite.aw.valid),
620 do_read.eq(axi_lite.ar.valid),
621 ),
622 # Start reading/writing immediately not to waste a cycle
623 If(do_write,
624 port_adr.eq(axi_lite.aw.addr[adr_shift:]),
625 If(axi_lite.w.valid,
626 axi_lite.aw.ready.eq(1),
627 axi_lite.w.ready.eq(1),
628 NextState("SEND-WRITE-RESPONSE")
629 )
630 ).Elif(do_read,
631 port_adr.eq(axi_lite.ar.addr[adr_shift:]),
632 axi_lite.ar.ready.eq(1),
633 NextState("SEND-READ-RESPONSE"),
634 )
635 )
636 fsm.act("SEND-READ-RESPONSE",
637 NextValue(last_was_read, 1),
638 # As long as we have correct address port.dat_r will be valid
639 port_adr.eq(axi_lite.ar.addr[adr_shift:]),
640 axi_lite.r.data.eq(port_dat_r),
641 axi_lite.r.resp.eq(RESP_OKAY),
642 axi_lite.r.valid.eq(1),
643 If(axi_lite.r.ready,
644 NextState("START-TRANSACTION")
645 )
646 )
647 fsm.act("SEND-WRITE-RESPONSE",
648 NextValue(last_was_read, 0),
649 axi_lite.b.valid.eq(1),
650 axi_lite.b.resp.eq(RESP_OKAY),
651 If(axi_lite.b.ready,
652 NextState("START-TRANSACTION")
653 )
654 )
655 return fsm, comb
656
657 class AXILite2CSR(Module):
658 def __init__(self, axi_lite=None, bus_csr=None):
659 if axi_lite is None:
660 axi_lite = AXILiteInterface()
661 if bus_csr is None:
662 bus_csr = csr_bus.Interface()
663
664 self.axi_lite = axi_lite
665 self.csr = bus_csr
666
667 fsm, comb = axi_lite_to_simple(self.axi_lite,
668 port_adr=self.csr.adr, port_dat_r=self.csr.dat_r,
669 port_dat_w=self.csr.dat_w, port_we=self.csr.we)
670 self.submodules.fsm = fsm
671 self.comb += comb
672
673 # AXILite SRAM -------------------------------------------------------------------------------------
674
675 class AXILiteSRAM(Module):
676 def __init__(self, mem_or_size, read_only=None, init=None, bus=None):
677 if bus is None:
678 bus = AXILiteInterface()
679 self.bus = bus
680
681 bus_data_width = len(self.bus.r.data)
682 if isinstance(mem_or_size, Memory):
683 assert(mem_or_size.width <= bus_data_width)
684 self.mem = mem_or_size
685 else:
686 self.mem = Memory(bus_data_width, mem_or_size//(bus_data_width//8), init=init)
687
688 if read_only is None:
689 if hasattr(self.mem, "bus_read_only"):
690 read_only = self.mem.bus_read_only
691 else:
692 read_only = False
693
694 ###
695
696 # Create memory port
697 port = self.mem.get_port(write_capable=not read_only, we_granularity=8,
698 mode=READ_FIRST if read_only else WRITE_FIRST)
699 self.specials += self.mem, port
700
701 # Generate write enable signal
702 if not read_only:
703 self.comb += port.dat_w.eq(self.bus.w.data),
704 self.comb += [port.we[i].eq(self.bus.w.valid & self.bus.w.ready & self.bus.w.strb[i])
705 for i in range(bus_data_width//8)]
706
707 # Transaction logic
708 fsm, comb = axi_lite_to_simple(self.bus,
709 port_adr=port.adr, port_dat_r=port.dat_r,
710 port_dat_w=port.dat_w if not read_only else None,
711 port_we=port.we if not read_only else None)
712 self.submodules.fsm = fsm
713 self.comb += comb
714
715 # AXILite Data Width Converter ---------------------------------------------------------------------
716
717 class _AXILiteDownConverterWrite(Module):
718 def __init__(self, master, slave):
719 assert isinstance(master, AXILiteInterface) and isinstance(slave, AXILiteInterface)
720 dw_from = len(master.w.data)
721 dw_to = len(slave.w.data)
722 ratio = dw_from//dw_to
723 master_align = log2_int(master.data_width//8)
724 slave_align = log2_int(slave.data_width//8)
725
726 skip = Signal()
727 counter = Signal(max=ratio)
728 aw_ready = Signal()
729 w_ready = Signal()
730 resp = Signal.like(master.b.resp)
731 addr_counter = Signal(master_align)
732
733 # # #
734
735 # Slave address counter
736 self.comb += addr_counter[slave_align:].eq(counter)
737
738 # Data path
739 self.comb += [
740 slave.aw.addr.eq(Cat(addr_counter, master.aw.addr[master_align:])),
741 Case(counter, {i: slave.w.data.eq(master.w.data[i*dw_to:]) for i in range(ratio)}),
742 Case(counter, {i: slave.w.strb.eq(master.w.strb[i*dw_to//8:]) for i in range(ratio)}),
743 master.b.resp.eq(resp),
744 ]
745
746 # Control Path
747 fsm = FSM(reset_state="IDLE")
748 fsm = ResetInserter()(fsm)
749 self.submodules.fsm = fsm
750 # Reset the converter state if master breaks a request, we can do that as
751 # aw.valid and w.valid are kept high in CONVERT and RESPOND-SLAVE, and
752 # acknowledged only when moving to RESPOND-MASTER, and then b.valid is 1
753 self.comb += fsm.reset.eq(~((master.aw.valid | master.w.valid) | master.b.valid))
754
755 fsm.act("IDLE",
756 NextValue(counter, 0),
757 NextValue(resp, RESP_OKAY),
758 If(master.aw.valid & master.w.valid,
759 NextState("CONVERT")
760 )
761 )
762 fsm.act("CONVERT",
763 skip.eq(slave.w.strb == 0),
764 slave.aw.valid.eq(~skip & ~aw_ready),
765 slave.w.valid.eq(~skip & ~w_ready),
766 If(slave.aw.ready,
767 NextValue(aw_ready, 1)
768 ),
769 If(slave.w.ready,
770 NextValue(w_ready, 1)
771 ),
772 # When skipping, we just increment the counter
773 If(skip,
774 NextValue(counter, counter + 1),
775 # Corner-case: when the last word is being skipped, we must send the response
776 If(counter == (ratio - 1),
777 master.aw.ready.eq(1),
778 master.w.ready.eq(1),
779 NextState("RESPOND-MASTER")
780 )
781 # Write current word and wait for write response
782 ).Elif((slave.aw.ready | aw_ready) & (slave.w.ready | w_ready),
783 NextState("RESPOND-SLAVE")
784 )
785 )
786 fsm.act("RESPOND-SLAVE",
787 NextValue(aw_ready, 0),
788 NextValue(w_ready, 0),
789 If(slave.b.valid,
790 slave.b.ready.eq(1),
791 # Errors are sticky, so the first one is always sent
792 If((resp == RESP_OKAY) & (slave.b.resp != RESP_OKAY),
793 NextValue(resp, slave.b.resp)
794 ),
795 If(counter == (ratio - 1),
796 master.aw.ready.eq(1),
797 master.w.ready.eq(1),
798 NextState("RESPOND-MASTER")
799 ).Else(
800 NextValue(counter, counter + 1),
801 NextState("CONVERT")
802 )
803 )
804 )
805 fsm.act("RESPOND-MASTER",
806 NextValue(aw_ready, 0),
807 NextValue(w_ready, 0),
808 master.b.valid.eq(1),
809 If(master.b.ready,
810 NextState("IDLE")
811 )
812 )
813
814 class _AXILiteDownConverterRead(Module):
815 def __init__(self, master, slave):
816 assert isinstance(master, AXILiteInterface) and isinstance(slave, AXILiteInterface)
817 dw_from = len(master.r.data)
818 dw_to = len(slave.r.data)
819 ratio = dw_from//dw_to
820 master_align = log2_int(master.data_width//8)
821 slave_align = log2_int(slave.data_width//8)
822
823 skip = Signal()
824 counter = Signal(max=ratio)
825 resp = Signal.like(master.r.resp)
826 addr_counter = Signal(master_align)
827
828 # # #
829
830 # Slave address counter
831 self.comb += addr_counter[slave_align:].eq(counter)
832
833 # Data path
834 # shift the data word
835 r_data = Signal(dw_from, reset_less=True)
836 self.sync += If(slave.r.ready, r_data.eq(master.r.data))
837 self.comb += master.r.data.eq(Cat(r_data[dw_to:], slave.r.data))
838 # address, resp
839 self.comb += [
840 slave.ar.addr.eq(Cat(addr_counter, master.ar.addr[master_align:])),
841 master.r.resp.eq(resp),
842 ]
843
844 # Control Path
845 fsm = FSM(reset_state="IDLE")
846 fsm = ResetInserter()(fsm)
847 self.submodules.fsm = fsm
848 # Reset the converter state if master breaks a request, we can do that as
849 # ar.valid is high in CONVERT and RESPOND-SLAVE, and r.valid in RESPOND-MASTER
850 self.comb += fsm.reset.eq(~(master.ar.valid | master.r.valid))
851
852 fsm.act("IDLE",
853 NextValue(counter, 0),
854 NextValue(resp, RESP_OKAY),
855 If(master.ar.valid,
856 NextState("CONVERT")
857 )
858 )
859 fsm.act("CONVERT",
860 slave.ar.valid.eq(1),
861 If(slave.ar.ready,
862 NextState("RESPOND-SLAVE")
863 )
864 )
865 fsm.act("RESPOND-SLAVE",
866 If(slave.r.valid,
867 # Errors are sticky, so the first one is always sent
868 If((resp == RESP_OKAY) & (slave.r.resp != RESP_OKAY),
869 NextValue(resp, slave.r.resp)
870 ),
871 # On last word acknowledge ar and hold slave.r.valid until we get master.r.ready
872 If(counter == (ratio - 1),
873 master.ar.ready.eq(1),
874 NextState("RESPOND-MASTER")
875 # Acknowledge the response and continue conversion
876 ).Else(
877 slave.r.ready.eq(1),
878 NextValue(counter, counter + 1),
879 NextState("CONVERT")
880 )
881 )
882 )
883 fsm.act("RESPOND-MASTER",
884 master.r.valid.eq(1),
885 If(master.r.ready,
886 slave.r.ready.eq(1),
887 NextState("IDLE")
888 )
889 )
890
891 class AXILiteDownConverter(Module):
892 def __init__(self, master, slave):
893 self.submodules.write = _AXILiteDownConverterWrite(master, slave)
894 self.submodules.read = _AXILiteDownConverterRead(master, slave)
895
896 class AXILiteUpConverter(Module):
897 # TODO: we could try joining multiple master accesses into single slave access
898 # would reuqire checking if address changes and a way to flush on single access
899 def __init__(self, master, slave):
900 assert isinstance(master, AXILiteInterface) and isinstance(slave, AXILiteInterface)
901 dw_from = len(master.r.data)
902 dw_to = len(slave.r.data)
903 ratio = dw_to//dw_from
904 master_align = log2_int(master.data_width//8)
905 slave_align = log2_int(slave.data_width//8)
906
907 wr_word = Signal(log2_int(ratio))
908 rd_word = Signal(log2_int(ratio))
909 wr_word_r = Signal(log2_int(ratio))
910 rd_word_r = Signal(log2_int(ratio))
911
912 # # #
913
914 self.comb += master.connect(slave, omit={"addr", "strb", "data"})
915
916 # Address
917 self.comb += [
918 slave.aw.addr[slave_align:].eq(master.aw.addr[slave_align:]),
919 slave.ar.addr[slave_align:].eq(master.ar.addr[slave_align:]),
920 ]
921
922 # Data path
923 wr_cases, rd_cases = {}, {}
924 for i in range(ratio):
925 strb_from = i * dw_from//8
926 strb_to = (i+1) * dw_from//8
927 data_from = i * dw_from
928 data_to = (i+1) * dw_from
929 wr_cases[i] = [
930 slave.w.strb[strb_from:strb_to].eq(master.w.strb),
931 slave.w.data[data_from:data_to].eq(master.w.data),
932 ]
933 rd_cases[i] = [
934 master.r.data.eq(slave.r.data[data_from:data_to]),
935 ]
936
937 # Switch current word based on the last valid master address
938 self.sync += If(master.aw.valid, wr_word_r.eq(wr_word))
939 self.sync += If(master.ar.valid, rd_word_r.eq(rd_word))
940 self.comb += [
941 Case(master.aw.valid, {
942 0: wr_word.eq(wr_word_r),
943 1: wr_word.eq(master.aw.addr[master_align:slave_align]),
944 }),
945 Case(master.ar.valid, {
946 0: rd_word.eq(rd_word_r),
947 1: rd_word.eq(master.ar.addr[master_align:slave_align]),
948 }),
949 ]
950
951 self.comb += Case(wr_word, wr_cases)
952 self.comb += Case(rd_word, rd_cases)
953
954 class AXILiteConverter(Module):
955 """AXILite data width converter"""
956 def __init__(self, master, slave):
957 self.master = master
958 self.slave = slave
959
960 # # #
961
962 dw_from = len(master.r.data)
963 dw_to = len(slave.r.data)
964 if dw_from > dw_to:
965 self.submodules += AXILiteDownConverter(master, slave)
966 elif dw_from < dw_to:
967 self.submodules += AXILiteUpConverter(master, slave)
968 else:
969 self.comb += master.connect(slave)
970
971 # AXILite Timeout ----------------------------------------------------------------------------------
972
973 class AXILiteTimeout(Module):
974 """Protect master against slave timeouts (master _has_ to respond correctly)"""
975 def __init__(self, master, cycles):
976 self.error = Signal()
977 wr_error = Signal()
978 rd_error = Signal()
979
980 # # #
981
982 self.comb += self.error.eq(wr_error | rd_error)
983
984 wr_timer = WaitTimer(int(cycles))
985 rd_timer = WaitTimer(int(cycles))
986 self.submodules += wr_timer, rd_timer
987
988 def channel_fsm(timer, wait_cond, error, response):
989 fsm = FSM(reset_state="WAIT")
990 fsm.act("WAIT",
991 timer.wait.eq(wait_cond),
992 # done is updated in `sync`, so we must make sure that `ready` has not been issued
993 # by slave during that single cycle, by checking `timer.wait`
994 If(timer.done & timer.wait,
995 error.eq(1),
996 NextState("RESPOND")
997 )
998 )
999 fsm.act("RESPOND", *response)
1000 return fsm
1001
1002 self.submodules.wr_fsm = channel_fsm(
1003 timer = wr_timer,
1004 wait_cond = (master.aw.valid & ~master.aw.ready) | (master.w.valid & ~master.w.ready),
1005 error = wr_error,
1006 response = [
1007 master.aw.ready.eq(master.aw.valid),
1008 master.w.ready.eq(master.w.valid),
1009 master.b.valid.eq(~master.aw.valid & ~master.w.valid),
1010 master.b.resp.eq(RESP_SLVERR),
1011 If(master.b.valid & master.b.ready,
1012 NextState("WAIT")
1013 )
1014 ])
1015
1016 self.submodules.rd_fsm = channel_fsm(
1017 timer = rd_timer,
1018 wait_cond = master.ar.valid & ~master.ar.ready,
1019 error = rd_error,
1020 response = [
1021 master.ar.ready.eq(master.ar.valid),
1022 master.r.valid.eq(~master.ar.valid),
1023 master.r.resp.eq(RESP_SLVERR),
1024 master.r.data.eq(2**len(master.r.data) - 1),
1025 If(master.r.valid & master.r.ready,
1026 NextState("WAIT")
1027 )
1028 ])
1029
1030 # AXILite Interconnect -----------------------------------------------------------------------------
1031
1032 class _AXILiteRequestCounter(Module):
1033 def __init__(self, request, response, max_requests=256):
1034 self.counter = counter = Signal(max=max_requests)
1035 self.full = full = Signal()
1036 self.empty = empty = Signal()
1037 self.stall = stall = Signal()
1038 self.ready = self.empty
1039
1040 self.comb += [
1041 full.eq(counter == max_requests - 1),
1042 empty.eq(counter == 0),
1043 stall.eq(request & full),
1044 ]
1045
1046 self.sync += [
1047 If(request & response,
1048 counter.eq(counter)
1049 ).Elif(request & ~full,
1050 counter.eq(counter + 1)
1051 ).Elif(response & ~empty,
1052 counter.eq(counter - 1)
1053 ),
1054 ]
1055
1056 class AXILiteInterconnectPointToPoint(Module):
1057 def __init__(self, master, slave):
1058 self.comb += master.connect(slave)
1059
1060 class AXILiteArbiter(Module):
1061 """AXI Lite arbiter
1062
1063 Arbitrate between master interfaces and connect one to the target.
1064 New master will not be selected until all requests have been responded to.
1065 Arbitration for write and read channels is done separately.
1066 """
1067 def __init__(self, masters, target):
1068 self.submodules.rr_write = roundrobin.RoundRobin(len(masters), roundrobin.SP_CE)
1069 self.submodules.rr_read = roundrobin.RoundRobin(len(masters), roundrobin.SP_CE)
1070
1071 def get_sig(interface, channel, name):
1072 return getattr(getattr(interface, channel), name)
1073
1074 # mux master->slave signals
1075 for channel, name, direction in target.layout_flat():
1076 rr = self.rr_write if channel in ["aw", "w", "b"] else self.rr_read
1077 if direction == DIR_M_TO_S:
1078 choices = Array(get_sig(m, channel, name) for m in masters)
1079 self.comb += get_sig(target, channel, name).eq(choices[rr.grant])
1080
1081 # connect slave->master signals
1082 for channel, name, direction in target.layout_flat():
1083 rr = self.rr_write if channel in ["aw", "w", "b"] else self.rr_read
1084 if direction == DIR_S_TO_M:
1085 source = get_sig(target, channel, name)
1086 for i, m in enumerate(masters):
1087 dest = get_sig(m, channel, name)
1088 if name == "ready":
1089 self.comb += dest.eq(source & (rr.grant == i))
1090 else:
1091 self.comb += dest.eq(source)
1092
1093 # allow to change rr.grant only after all requests from a master have been responded to
1094 self.submodules.wr_lock = wr_lock = _AXILiteRequestCounter(
1095 request=target.aw.valid & target.aw.ready, response=target.b.valid & target.b.ready)
1096 self.submodules.rd_lock = rd_lock = _AXILiteRequestCounter(
1097 request=target.ar.valid & target.ar.ready, response=target.r.valid & target.r.ready)
1098
1099 # switch to next request only if there are no responses pending
1100 self.comb += [
1101 self.rr_write.ce.eq(~(target.aw.valid | target.w.valid | target.b.valid) & wr_lock.ready),
1102 self.rr_read.ce.eq(~(target.ar.valid | target.r.valid) & rd_lock.ready),
1103 ]
1104
1105 # connect bus requests to round-robin selectors
1106 self.comb += [
1107 self.rr_write.request.eq(Cat(*[m.aw.valid | m.w.valid | m.b.valid for m in masters])),
1108 self.rr_read.request.eq(Cat(*[m.ar.valid | m.r.valid for m in masters])),
1109 ]
1110
1111 class AXILiteDecoder(Module):
1112 _doc_slaves = """
1113 slaves: [(decoder, slave), ...]
1114 List of slaves with address decoders, where `decoder` is a function:
1115 decoder(Signal(address_width - log2(data_width//8))) -> Signal(1)
1116 that returns 1 when the slave is selected and 0 otherwise.
1117 """.strip()
1118
1119 __doc__ = """AXI Lite decoder
1120
1121 Decode master access to particular slave based on its decoder function.
1122
1123 {slaves}
1124 """.format(slaves=_doc_slaves)
1125
1126 def __init__(self, master, slaves, register=False):
1127 # TODO: unused register argument
1128 addr_shift = log2_int(master.data_width//8)
1129
1130 channels = {
1131 "write": {"aw", "w", "b"},
1132 "read": {"ar", "r"},
1133 }
1134 # reverse mapping: directions[channel] -> "write"/"read"
1135 directions = {ch: d for d, chs in channels.items() for ch in chs}
1136
1137 def new_slave_sel():
1138 return {"write": Signal(len(slaves)), "read": Signal(len(slaves))}
1139
1140 slave_sel_dec = new_slave_sel()
1141 slave_sel_reg = new_slave_sel()
1142 slave_sel = new_slave_sel()
1143
1144 # we need to hold the slave selected until all responses come back
1145 # TODO: we could reuse arbiter counters
1146 locks = {
1147 "write": _AXILiteRequestCounter(
1148 request=master.aw.valid & master.aw.ready,
1149 response=master.b.valid & master.b.ready),
1150 "read": _AXILiteRequestCounter(
1151 request=master.ar.valid & master.ar.ready,
1152 response=master.r.valid & master.r.ready),
1153 }
1154 self.submodules += locks.values()
1155
1156 def get_sig(interface, channel, name):
1157 return getattr(getattr(interface, channel), name)
1158
1159 # # #
1160
1161 # decode slave addresses
1162 for i, (decoder, bus) in enumerate(slaves):
1163 self.comb += [
1164 slave_sel_dec["write"][i].eq(decoder(master.aw.addr[addr_shift:])),
1165 slave_sel_dec["read"][i].eq(decoder(master.ar.addr[addr_shift:])),
1166 ]
1167
1168 # change the current selection only when we've got all responses
1169 for channel in locks.keys():
1170 self.sync += If(locks[channel].ready, slave_sel_reg[channel].eq(slave_sel_dec[channel]))
1171 # we have to cut the delaying select
1172 for ch, final in slave_sel.items():
1173 self.comb += If(locks[ch].ready,
1174 final.eq(slave_sel_dec[ch])
1175 ).Else(
1176 final.eq(slave_sel_reg[ch])
1177 )
1178
1179 # connect master->slaves signals except valid/ready
1180 for i, (_, slave) in enumerate(slaves):
1181 for channel, name, direction in master.layout_flat():
1182 if direction == DIR_M_TO_S:
1183 src = get_sig(master, channel, name)
1184 dst = get_sig(slave, channel, name)
1185 # mask master control signals depending on slave selection
1186 if name in ["valid", "ready"]:
1187 src = src & slave_sel[directions[channel]][i]
1188 self.comb += dst.eq(src)
1189
1190 # connect slave->master signals masking not selected slaves
1191 for channel, name, direction in master.layout_flat():
1192 if direction == DIR_S_TO_M:
1193 dst = get_sig(master, channel, name)
1194 masked = []
1195 for i, (_, slave) in enumerate(slaves):
1196 src = get_sig(slave, channel, name)
1197 # mask depending on channel
1198 mask = Replicate(slave_sel[directions[channel]][i], len(dst))
1199 masked.append(src & mask)
1200 self.comb += dst.eq(reduce(or_, masked))
1201
1202 class AXILiteInterconnectShared(Module):
1203 __doc__ = """AXI Lite shared interconnect
1204
1205 {slaves}
1206 """.format(slaves=AXILiteDecoder._doc_slaves)
1207
1208 def __init__(self, masters, slaves, register=False, timeout_cycles=1e6):
1209 # TODO: data width
1210 shared = AXILiteInterface()
1211 self.submodules.arbiter = AXILiteArbiter(masters, shared)
1212 self.submodules.decoder = AXILiteDecoder(shared, slaves)
1213 if timeout_cycles is not None:
1214 self.submodules.timeout = AXILiteTimeout(shared, timeout_cycles)
1215
1216 class AXILiteCrossbar(Module):
1217 __doc__ = """AXI Lite crossbar
1218
1219 MxN crossbar for M masters and N slaves.
1220
1221 {slaves}
1222 """.format(slaves=AXILiteDecoder._doc_slaves)
1223
1224 def __init__(self, masters, slaves, register=False, timeout_cycles=1e6):
1225 matches, busses = zip(*slaves)
1226 access_m_s = [[AXILiteInterface() for j in slaves] for i in masters] # a[master][slave]
1227 access_s_m = list(zip(*access_m_s)) # a[slave][master]
1228 # decode each master into its access row
1229 for slaves, master in zip(access_m_s, masters):
1230 slaves = list(zip(matches, slaves))
1231 self.submodules += AXILiteDecoder(master, slaves, register)
1232 # arbitrate each access column onto its slave
1233 for masters, bus in zip(access_s_m, busses):
1234 self.submodules += AXILiteArbiter(masters, bus)