-# This file is Copyright (c) 2015-2018 Florent Kermarrec <florent@enjoy-digital.fr>
+# This file is Copyright (c) 2015-2020 Florent Kermarrec <florent@enjoy-digital.fr>
# License: BSD
+from math import log2
+
from migen import *
-from migen.genlib.misc import chooser, WaitTimer
-from migen.genlib.record import Record
-from migen.genlib.fsm import FSM, NextState
+from migen.genlib.misc import WaitTimer
from litex.soc.interconnect import wishbone
from litex.soc.interconnect import stream
+# Wishbone Streaming Bridge ------------------------------------------------------------------------
-class WishboneStreamingBridge(Module):
- cmds = {
- "write": 0x01,
- "read": 0x02
- }
+CMD_WRITE = 0x01
+CMD_READ = 0x02
- def __init__(self, phy, clk_freq):
+class WishboneStreamingBridge(Module):
+ def __init__(self, phy, clk_freq, data_width=32, address_width=32):
self.wishbone = wishbone.Interface()
+ self.comb += phy.source.ready.eq(1) # Always accept incoming stream.
# # #
- byte_counter = Signal(3, reset_less=True)
- byte_counter_reset = Signal()
- byte_counter_ce = Signal()
- self.sync += \
- If(byte_counter_reset,
- byte_counter.eq(0)
- ).Elif(byte_counter_ce,
- byte_counter.eq(byte_counter + 1)
- )
-
- word_counter = Signal(3, reset_less=True)
- word_counter_reset = Signal()
- word_counter_ce = Signal()
- self.sync += \
- If(word_counter_reset,
- word_counter.eq(0)
- ).Elif(word_counter_ce,
- word_counter.eq(word_counter + 1)
- )
-
- cmd = Signal(8, reset_less=True)
- cmd_ce = Signal()
-
- length = Signal(8, reset_less=True)
- length_ce = Signal()
+ cmd = Signal(8, reset_less=True)
+ length = Signal(8, reset_less=True)
+ address = Signal(address_width, reset_less=True)
+ data = Signal(data_width, reset_less=True)
+ bytes_count = Signal(int(log2(data_width//8)), reset_less=True)
+ words_count = Signal(8, reset_less=True)
- address = Signal(32, reset_less=True)
- address_ce = Signal()
+ bytes_count_done = (bytes_count == (data_width//8 - 1))
+ words_count_done = (words_count == (length - 1))
- data = Signal(32, reset_less=True)
- rx_data_ce = Signal()
- tx_data_ce = Signal()
-
- self.sync += [
- If(cmd_ce, cmd.eq(phy.source.data)),
- If(length_ce, length.eq(phy.source.data)),
- If(address_ce, address.eq(Cat(phy.source.data, address[0:24]))),
- If(rx_data_ce,
- data.eq(Cat(phy.source.data, data[0:24]))
- ).Elif(tx_data_ce,
- data.eq(self.wishbone.dat_r)
- )
- ]
-
- fsm = ResetInserter()(FSM(reset_state="IDLE"))
- timer = WaitTimer(int(clk_freq//10))
+ fsm = ResetInserter()(FSM(reset_state="RECEIVE-CMD"))
+ timer = WaitTimer(int(100e-3*clk_freq))
+ self.comb += timer.wait.eq(~fsm.ongoing("RECEIVE-CMD"))
self.submodules += fsm, timer
- self.comb += [
- fsm.reset.eq(timer.done),
- phy.source.ready.eq(1)
- ]
- fsm.act("IDLE",
+ self.comb += fsm.reset.eq(timer.done)
+ fsm.act("RECEIVE-CMD",
+ NextValue(bytes_count, 0),
+ NextValue(words_count, 0),
If(phy.source.valid,
- cmd_ce.eq(1),
- If((phy.source.data == self.cmds["write"]) |
- (phy.source.data == self.cmds["read"]),
- NextState("RECEIVE_LENGTH")
- ),
- byte_counter_reset.eq(1),
- word_counter_reset.eq(1)
+ NextValue(cmd, phy.source.data),
+ NextState("RECEIVE-LENGTH")
)
)
- fsm.act("RECEIVE_LENGTH",
+ fsm.act("RECEIVE-LENGTH",
If(phy.source.valid,
- length_ce.eq(1),
- NextState("RECEIVE_ADDRESS")
+ NextValue(length, phy.source.data),
+ NextState("RECEIVE-ADDRESS")
)
)
- fsm.act("RECEIVE_ADDRESS",
+ fsm.act("RECEIVE-ADDRESS",
If(phy.source.valid,
- address_ce.eq(1),
- byte_counter_ce.eq(1),
- If(byte_counter == 3,
- If(cmd == self.cmds["write"],
- NextState("RECEIVE_DATA")
- ).Elif(cmd == self.cmds["read"],
- NextState("READ_DATA")
- ),
- byte_counter_reset.eq(1),
+ NextValue(address, Cat(phy.source.data, address)),
+ NextValue(bytes_count, bytes_count + 1),
+ If(bytes_count_done,
+ If(cmd == CMD_WRITE,
+ NextState("RECEIVE-DATA")
+ ).Elif(cmd == CMD_READ,
+ NextState("READ-DATA")
+ ).Else(
+ NextState("RECEIVE-CMD")
+ )
)
)
)
- fsm.act("RECEIVE_DATA",
+ fsm.act("RECEIVE-DATA",
If(phy.source.valid,
- rx_data_ce.eq(1),
- byte_counter_ce.eq(1),
- If(byte_counter == 3,
- NextState("WRITE_DATA"),
- byte_counter_reset.eq(1)
+ NextValue(data, Cat(phy.source.data, data)),
+ NextValue(bytes_count, bytes_count + 1),
+ If(bytes_count_done,
+ NextState("WRITE-DATA")
)
)
)
self.comb += [
- self.wishbone.adr.eq(address + word_counter),
+ self.wishbone.adr.eq(address),
self.wishbone.dat_w.eq(data),
- self.wishbone.sel.eq(2**len(self.wishbone.sel) - 1)
+ self.wishbone.sel.eq(2**(data_width//8) - 1)
]
- fsm.act("WRITE_DATA",
+ fsm.act("WRITE-DATA",
self.wishbone.stb.eq(1),
self.wishbone.we.eq(1),
self.wishbone.cyc.eq(1),
If(self.wishbone.ack,
- word_counter_ce.eq(1),
- If(word_counter == (length-1),
- NextState("IDLE")
+ NextValue(words_count, words_count + 1),
+ NextValue(address, address + 1),
+ If(words_count_done,
+ NextState("RECEIVE-CMD")
).Else(
- NextState("RECEIVE_DATA")
+ NextState("RECEIVE-DATA")
)
)
)
- fsm.act("READ_DATA",
+ fsm.act("READ-DATA",
self.wishbone.stb.eq(1),
self.wishbone.we.eq(0),
self.wishbone.cyc.eq(1),
If(self.wishbone.ack,
- tx_data_ce.eq(1),
- NextState("SEND_DATA")
+ NextValue(data, self.wishbone.dat_r),
+ NextState("SEND-DATA")
)
)
- self.comb += \
- chooser(data, byte_counter, phy.sink.data, n=4, reverse=True)
- fsm.act("SEND_DATA",
+ cases = {}
+ for i, n in enumerate(reversed(range(data_width//8))):
+ cases[i] = phy.sink.data.eq(data[8*n:])
+ self.comb += Case(bytes_count, cases)
+ fsm.act("SEND-DATA",
phy.sink.valid.eq(1),
If(phy.sink.ready,
- byte_counter_ce.eq(1),
- If(byte_counter == 3,
- word_counter_ce.eq(1),
- If(word_counter == (length-1),
- NextState("IDLE")
+ NextValue(bytes_count, bytes_count + 1),
+ If(bytes_count_done,
+ NextValue(words_count, words_count + 1),
+ NextValue(address, address + 1),
+ If(words_count_done,
+ NextState("RECEIVE-CMD")
).Else(
- NextState("READ_DATA"),
- byte_counter_reset.eq(1)
+ NextState("READ-DATA")
)
)
)
)
-
- self.comb += timer.wait.eq(~fsm.ongoing("IDLE"))
-
- self.comb += phy.sink.last.eq((byte_counter == 3) & (word_counter == length - 1))
-
+ self.comb += phy.sink.last.eq(bytes_count_done & words_count_done)
if hasattr(phy.sink, "length"):
- self.comb += phy.sink.length.eq(4*length)
+ self.comb += phy.sink.length.eq((data_width//8)*length)