soc/integration: add bus standard parser arguments
[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):
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))
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):
111 return _connect_axi(self, slave)
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):
187 return _connect_axi(self, slave)
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 AXILiteDownConverter(Module):
718 def __init__(self, master, slave):
719 assert isinstance(master, AXILiteInterface) and isinstance(slave, AXILiteInterface)
720 dw_from = len(master.r.data)
721 dw_to = len(slave.r.data)
722 ratio = dw_from//dw_to
723
724 # # #
725
726 skip = Signal()
727 counter = Signal(max=ratio)
728 do_read = Signal()
729 do_write = Signal()
730 last_was_read = Signal()
731 aw_ready = Signal()
732 w_ready = Signal()
733 resp = Signal.like(master.b.resp)
734
735 # Slave address counter
736 master_align = log2_int(master.data_width//8)
737 slave_align = log2_int(slave.data_width//8)
738 addr_counter = Signal(master_align)
739 self.comb += addr_counter[slave_align:].eq(counter)
740
741 # Write path
742 self.comb += [
743 slave.aw.addr.eq(Cat(addr_counter, master.aw.addr[master_align:])),
744 Case(counter, {i: slave.w.data.eq(master.w.data[i*dw_to:]) for i in range(ratio)}),
745 Case(counter, {i: slave.w.strb.eq(master.w.strb[i*dw_to//8:]) for i in range(ratio)}),
746 master.b.resp.eq(resp),
747 ]
748
749 # Read path
750 # shift the data word
751 r_data = Signal(dw_from, reset_less=True)
752 self.sync += If(slave.r.ready, r_data.eq(master.r.data))
753 self.comb += master.r.data.eq(Cat(r_data[dw_to:], slave.r.data))
754 # address, resp
755 self.comb += [
756 slave.ar.addr.eq(Cat(addr_counter, master.ar.addr[master_align:])),
757 master.r.resp.eq(resp),
758 ]
759
760 # Control Path
761 fsm = FSM(reset_state="IDLE")
762 fsm = ResetInserter()(fsm)
763 self.submodules.fsm = fsm
764 self.comb += fsm.reset.eq(~(master.aw.valid | master.ar.valid))
765
766 fsm.act("IDLE",
767 NextValue(counter, 0),
768 NextValue(resp, RESP_OKAY),
769 # If the last access was a read, do a write, and vice versa
770 If(master.aw.valid & master.ar.valid,
771 do_write.eq(last_was_read),
772 do_read.eq(~last_was_read),
773 ).Else(
774 do_write.eq(master.aw.valid),
775 do_read.eq(master.ar.valid),
776 ),
777 # Start reading/writing immediately not to waste a cycle
778 If(do_write & master.w.valid,
779 NextValue(last_was_read, 0),
780 NextState("WRITE")
781 ).Elif(do_read,
782 NextValue(last_was_read, 1),
783 NextState("READ")
784 )
785 )
786
787 # Write conversion
788 fsm.act("WRITE",
789 skip.eq(slave.w.strb == 0),
790 slave.aw.valid.eq(~skip & ~aw_ready),
791 slave.w.valid.eq(~skip & ~w_ready),
792 If(slave.aw.ready,
793 NextValue(aw_ready, 1)
794 ),
795 If(slave.w.ready,
796 NextValue(w_ready, 1)
797 ),
798 # When skipping, we just increment the counter
799 If(skip,
800 NextValue(counter, counter + 1),
801 # Corner-case: when the last word is being skipped, we must send the response
802 If(counter == (ratio - 1),
803 master.aw.ready.eq(1),
804 master.w.ready.eq(1),
805 NextState("WRITE-RESPONSE-MASTER")
806 )
807 # Write current word and wait for write response
808 ).Elif((slave.aw.ready | aw_ready) & (slave.w.ready | w_ready),
809 NextState("WRITE-RESPONSE-SLAVE")
810 )
811 )
812 fsm.act("WRITE-RESPONSE-SLAVE",
813 NextValue(aw_ready, 0),
814 NextValue(w_ready, 0),
815 If(slave.b.valid,
816 slave.b.ready.eq(1),
817 # Any errors is sticky, so the first one is always sent
818 If((resp == RESP_OKAY) & (slave.b.resp != RESP_OKAY),
819 NextValue(resp, slave.b.resp)
820 ),
821 If(counter == (ratio - 1),
822 master.aw.ready.eq(1),
823 master.w.ready.eq(1),
824 NextState("WRITE-RESPONSE-MASTER")
825 ).Else(
826 NextValue(counter, counter + 1),
827 NextState("WRITE")
828 )
829 )
830 )
831 fsm.act("WRITE-RESPONSE-MASTER",
832 NextValue(aw_ready, 0),
833 NextValue(w_ready, 0),
834 master.b.valid.eq(1),
835 If(master.b.ready,
836 NextState("IDLE")
837 )
838 )
839
840 # Read conversion
841 fsm.act("READ",
842 slave.ar.valid.eq(1),
843 If(slave.ar.ready,
844 NextState("READ-RESPONSE-SLAVE")
845 )
846 )
847 fsm.act("READ-RESPONSE-SLAVE",
848 If(slave.r.valid,
849 # Any errors is sticky, so the first one is always sent
850 If((resp == RESP_OKAY) & (slave.b.resp != RESP_OKAY),
851 NextValue(resp, slave.b.resp)
852 ),
853 # On last word acknowledge ar and hold slave.r.valid until we get master.r.ready
854 If(counter == (ratio - 1),
855 master.ar.ready.eq(1),
856 NextState("READ-RESPONSE-MASTER")
857 # Acknowledge the response and continue conversion
858 ).Else(
859 slave.r.ready.eq(1),
860 NextValue(counter, counter + 1),
861 NextState("READ")
862 )
863 )
864 )
865 fsm.act("READ-RESPONSE-MASTER",
866 master.r.valid.eq(1),
867 If(master.r.ready,
868 slave.r.ready.eq(1),
869 NextState("IDLE")
870 )
871 )
872
873 class AXILiteConverter(Module):
874 """AXILite data width converter"""
875 def __init__(self, master, slave):
876 self.master = master
877 self.slave = slave
878
879 # # #
880
881 dw_from = len(master.r.data)
882 dw_to = len(slave.r.data)
883 if dw_from > dw_to:
884 self.submodules += AXILiteDownConverter(master, slave)
885 elif dw_from < dw_to:
886 raise NotImplementedError("AXILiteUpConverter")
887 else:
888 self.comb += master.connect(slave)
889
890 # AXILite Timeout ----------------------------------------------------------------------------------
891
892 class AXILiteTimeout(Module):
893 """Protect master against slave timeouts (master _has_ to respond correctly)"""
894 def __init__(self, master, cycles):
895 self.error = Signal()
896 wr_error = Signal()
897 rd_error = Signal()
898
899 # # #
900
901 self.comb += self.error.eq(wr_error | rd_error)
902
903 wr_timer = WaitTimer(int(cycles))
904 rd_timer = WaitTimer(int(cycles))
905 self.submodules += wr_timer, rd_timer
906
907 def channel_fsm(timer, wait_cond, error, response):
908 fsm = FSM(reset_state="WAIT")
909 fsm.act("WAIT",
910 timer.wait.eq(wait_cond),
911 # done is updated in `sync`, so we must make sure that `ready` has not been issued
912 # by slave during that single cycle, by checking `timer.wait`
913 If(timer.done & timer.wait,
914 error.eq(1),
915 NextState("RESPOND")
916 )
917 )
918 fsm.act("RESPOND", *response)
919 return fsm
920
921 self.submodules.wr_fsm = channel_fsm(
922 timer = wr_timer,
923 wait_cond = (master.aw.valid & ~master.aw.ready) | (master.w.valid & ~master.w.ready),
924 error = wr_error,
925 response = [
926 master.aw.ready.eq(master.aw.valid),
927 master.w.ready.eq(master.w.valid),
928 master.b.valid.eq(~master.aw.valid & ~master.w.valid),
929 master.b.resp.eq(RESP_SLVERR),
930 If(master.b.valid & master.b.ready,
931 NextState("WAIT")
932 )
933 ])
934
935 self.submodules.rd_fsm = channel_fsm(
936 timer = rd_timer,
937 wait_cond = master.ar.valid & ~master.ar.ready,
938 error = rd_error,
939 response = [
940 master.ar.ready.eq(master.ar.valid),
941 master.r.valid.eq(~master.ar.valid),
942 master.r.resp.eq(RESP_SLVERR),
943 master.r.data.eq(2**len(master.r.data) - 1),
944 If(master.r.valid & master.r.ready,
945 NextState("WAIT")
946 )
947 ])
948
949 # AXILite Interconnect -----------------------------------------------------------------------------
950
951 class AXILiteInterconnectPointToPoint(Module):
952 def __init__(self, master, slave):
953 self.comb += master.connect(slave)
954
955
956 class AXILiteRequestCounter(Module):
957 def __init__(self, request, response, max_requests=256):
958 self.counter = counter = Signal(max=max_requests)
959 self.full = full = Signal()
960 self.empty = empty = Signal()
961 self.stall = stall = Signal()
962 self.ready = self.empty
963
964 self.comb += [
965 full.eq(counter == max_requests - 1),
966 empty.eq(counter == 0),
967 stall.eq(request & full),
968 ]
969
970 self.sync += [
971 If(request & response,
972 counter.eq(counter)
973 ).Elif(request & ~full,
974 counter.eq(counter + 1)
975 ).Elif(response & ~empty,
976 counter.eq(counter - 1)
977 ),
978 ]
979
980 class AXILiteArbiter(Module):
981 """AXI Lite arbiter
982
983 Arbitrate between master interfaces and connect one to the target.
984 New master will not be selected until all requests have been responded to.
985 Arbitration for write and read channels is done separately.
986 """
987 def __init__(self, masters, target):
988 self.submodules.rr_write = roundrobin.RoundRobin(len(masters), roundrobin.SP_CE)
989 self.submodules.rr_read = roundrobin.RoundRobin(len(masters), roundrobin.SP_CE)
990
991 def get_sig(interface, channel, name):
992 return getattr(getattr(interface, channel), name)
993
994 # mux master->slave signals
995 for channel, name, direction in target.layout_flat():
996 rr = self.rr_write if channel in ["aw", "w", "b"] else self.rr_read
997 if direction == DIR_M_TO_S:
998 choices = Array(get_sig(m, channel, name) for m in masters)
999 self.comb += get_sig(target, channel, name).eq(choices[rr.grant])
1000
1001 # connect slave->master signals
1002 for channel, name, direction in target.layout_flat():
1003 rr = self.rr_write if channel in ["aw", "w", "b"] else self.rr_read
1004 if direction == DIR_S_TO_M:
1005 source = get_sig(target, channel, name)
1006 for i, m in enumerate(masters):
1007 dest = get_sig(m, channel, name)
1008 if name == "ready":
1009 self.comb += dest.eq(source & (rr.grant == i))
1010 else:
1011 self.comb += dest.eq(source)
1012
1013 # allow to change rr.grant only after all requests from a master have been responded to
1014 self.submodules.wr_lock = wr_lock = AXILiteRequestCounter(
1015 request=target.aw.valid & target.aw.ready, response=target.b.valid & target.b.ready)
1016 self.submodules.rd_lock = rd_lock = AXILiteRequestCounter(
1017 request=target.ar.valid & target.ar.ready, response=target.r.valid & target.r.ready)
1018
1019 # switch to next request only if there are no responses pending
1020 self.comb += [
1021 self.rr_write.ce.eq(~(target.aw.valid | target.w.valid | target.b.valid) & wr_lock.ready),
1022 self.rr_read.ce.eq(~(target.ar.valid | target.r.valid) & rd_lock.ready),
1023 ]
1024
1025 # connect bus requests to round-robin selectors
1026 self.comb += [
1027 self.rr_write.request.eq(Cat(*[m.aw.valid | m.w.valid | m.b.valid for m in masters])),
1028 self.rr_read.request.eq(Cat(*[m.ar.valid | m.r.valid for m in masters])),
1029 ]
1030
1031 class AXILiteDecoder(Module):
1032 _doc_slaves = """
1033 slaves: [(decoder, slave), ...]
1034 List of slaves with address decoders, where `decoder` is a function:
1035 decoder(Signal(address_width - log2(data_width//8))) -> Signal(1)
1036 that returns 1 when the slave is selected and 0 otherwise.
1037 """.strip()
1038
1039 __doc__ = """AXI Lite decoder
1040
1041 Decode master access to particular slave based on its decoder function.
1042
1043 {slaves}
1044 """.format(slaves=_doc_slaves)
1045
1046 def __init__(self, master, slaves, register=False):
1047 # TODO: unused register argument
1048 addr_shift = log2_int(master.data_width//8)
1049
1050 channels = {
1051 "write": {"aw", "w", "b"},
1052 "read": {"ar", "r"},
1053 }
1054 # reverse mapping: directions[channel] -> "write"/"read"
1055 directions = {ch: d for d, chs in channels.items() for ch in chs}
1056
1057 def new_slave_sel():
1058 return {"write": Signal(len(slaves)), "read": Signal(len(slaves))}
1059
1060 slave_sel_dec = new_slave_sel()
1061 slave_sel_reg = new_slave_sel()
1062 slave_sel = new_slave_sel()
1063
1064 # we need to hold the slave selected until all responses come back
1065 # TODO: we could reuse arbiter counters
1066 locks = {
1067 "write": AXILiteRequestCounter(
1068 request=master.aw.valid & master.aw.ready,
1069 response=master.b.valid & master.b.ready),
1070 "read": AXILiteRequestCounter(
1071 request=master.ar.valid & master.ar.ready,
1072 response=master.r.valid & master.r.ready),
1073 }
1074 self.submodules += locks.values()
1075
1076 def get_sig(interface, channel, name):
1077 return getattr(getattr(interface, channel), name)
1078
1079 # # #
1080
1081 # decode slave addresses
1082 for i, (decoder, bus) in enumerate(slaves):
1083 self.comb += [
1084 slave_sel_dec["write"][i].eq(decoder(master.aw.addr[addr_shift:])),
1085 slave_sel_dec["read"][i].eq(decoder(master.ar.addr[addr_shift:])),
1086 ]
1087
1088 # change the current selection only when we've got all responses
1089 for channel in locks.keys():
1090 self.sync += If(locks[channel].ready, slave_sel_reg[channel].eq(slave_sel_dec[channel]))
1091 # we have to cut the delaying select
1092 for ch, final in slave_sel.items():
1093 self.comb += If(locks[ch].ready,
1094 final.eq(slave_sel_dec[ch])
1095 ).Else(
1096 final.eq(slave_sel_reg[ch])
1097 )
1098
1099 # connect master->slaves signals except valid/ready
1100 for i, (_, slave) in enumerate(slaves):
1101 for channel, name, direction in master.layout_flat():
1102 if direction == DIR_M_TO_S:
1103 src = get_sig(master, channel, name)
1104 dst = get_sig(slave, channel, name)
1105 # mask master control signals depending on slave selection
1106 if name in ["valid", "ready"]:
1107 src = src & slave_sel[directions[channel]][i]
1108 self.comb += dst.eq(src)
1109
1110 # connect slave->master signals masking not selected slaves
1111 for channel, name, direction in master.layout_flat():
1112 if direction == DIR_S_TO_M:
1113 dst = get_sig(master, channel, name)
1114 masked = []
1115 for i, (_, slave) in enumerate(slaves):
1116 src = get_sig(slave, channel, name)
1117 # mask depending on channel
1118 mask = Replicate(slave_sel[directions[channel]][i], len(dst))
1119 masked.append(src & mask)
1120 self.comb += dst.eq(reduce(or_, masked))
1121
1122 class AXILiteInterconnectShared(Module):
1123 __doc__ = """AXI Lite shared interconnect
1124
1125 {slaves}
1126 """.format(slaves=AXILiteDecoder._doc_slaves)
1127
1128 def __init__(self, masters, slaves, register=False, timeout_cycles=1e6):
1129 # TODO: data width
1130 shared = AXILiteInterface()
1131 self.submodules.arbiter = AXILiteArbiter(masters, shared)
1132 self.submodules.decoder = AXILiteDecoder(shared, slaves)
1133 if timeout_cycles is not None:
1134 self.submodules.timeout = AXILiteTimeout(shared, timeout_cycles)
1135
1136 class AXILiteCrossbar(Module):
1137 __doc__ = """AXI Lite crossbar
1138
1139 MxN crossbar for M masters and N slaves.
1140
1141 {slaves}
1142 """.format(slaves=AXILiteDecoder._doc_slaves)
1143
1144 def __init__(self, masters, slaves, register=False, timeout_cycles=1e6):
1145 matches, busses = zip(*slaves)
1146 access_m_s = [[AXILiteInterface() for j in slaves] for i in masters] # a[master][slave]
1147 access_s_m = list(zip(*access_m_s)) # a[slave][master]
1148 # decode each master into its access row
1149 for slaves, master in zip(access_m_s, masters):
1150 slaves = list(zip(matches, slaves))
1151 self.submodules += AXILiteDecoder(master, slaves, register)
1152 # arbitrate each access column onto its slave
1153 for masters, bus in zip(access_s_m, busses):
1154 self.submodules += AXILiteArbiter(masters, bus)