From 873d95e517b3e6074c3b07502c4a5f05aef09bf4 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 12 May 2020 12:53:01 +0200 Subject: [PATCH] interconnect/wishbonebridge: refresh/simplify. This should also improve Wishbone timings. Tested on iCEBreaker: ./icebreaker.py --cpu-type=None --uart-name=uartbone --csr-csv=csr.csv --build --flash With the following script: #!/usr/bin/env python3 import sys from litex import RemoteClient wb = RemoteClient() wb.open() # # # print("scratch: 0x{:08x}".format(wb.regs.ctrl_scratch.read())) errors = 0 for i in range(2): for j in range(32): wb.write(wb.mems.sram.base + 4*j, i + j) for j in range(32): if wb.read(wb.mems.sram.base + 4*j) != (i + j): errors += 1 print("sram errors: {:d}".format(errors)) # # # wb.close() --- litex/soc/interconnect/wishbonebridge.py | 234 ++++++++++------------- 1 file changed, 97 insertions(+), 137 deletions(-) diff --git a/litex/soc/interconnect/wishbonebridge.py b/litex/soc/interconnect/wishbonebridge.py index 00ec4a0ce..153a94397 100644 --- a/litex/soc/interconnect/wishbonebridge.py +++ b/litex/soc/interconnect/wishbonebridge.py @@ -1,167 +1,127 @@ -# This file is Copyright (c) 2015-2018 Florent Kermarrec +# This file is Copyright (c) 2015-2020 Florent Kermarrec # 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 ------------------------------------------------------------------------ + +CMD_WRITE = 0x01 +CMD_READ = 0x02 class WishboneStreamingBridge(Module): - cmds = { - "write": 0x01, - "read": 0x02 - } - - def __init__(self, phy, clk_freq): + 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) - ) + 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) - 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) - ) + bytes_count_done = (bytes_count == (data_width//8 - 1)) + words_count_done = (words_count == (length - 1)) - cmd = Signal(8, reset_less=True) - cmd_ce = Signal() - - length = Signal(8, reset_less=True) - length_ce = Signal() - - address = Signal(32, reset_less=True) - address_ce = Signal() - - 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), - ) - ) - ) - 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) - ) - ) - ) - self.comb += [ - self.wishbone.adr.eq(address + word_counter), - self.wishbone.dat_w.eq(data), - self.wishbone.sel.eq(2**len(self.wishbone.sel) - 1) - ] - 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") - ).Else( - NextState("RECEIVE_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") - ) - ) - self.comb += \ - chooser(data, byte_counter, phy.sink.data, n=4, reverse=True) - 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(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("READ_DATA"), - byte_counter_reset.eq(1) + NextState("RECEIVE-CMD") ) ) ) ) - - self.comb += timer.wait.eq(~fsm.ongoing("IDLE")) - - self.comb += phy.sink.last.eq((byte_counter == 3) & (word_counter == length - 1)) - + fsm.act("RECEIVE-DATA", + If(phy.source.valid, + 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), + self.wishbone.dat_w.eq(data), + self.wishbone.sel.eq(2**(data_width//8) - 1) + ] + fsm.act("WRITE-DATA", + self.wishbone.stb.eq(1), + self.wishbone.we.eq(1), + self.wishbone.cyc.eq(1), + If(self.wishbone.ack, + NextValue(words_count, words_count + 1), + NextValue(address, address + 1), + If(words_count_done, + NextState("RECEIVE-CMD") + ).Else( + NextState("RECEIVE-DATA") + ) + ) + ) + fsm.act("READ-DATA", + self.wishbone.stb.eq(1), + self.wishbone.we.eq(0), + self.wishbone.cyc.eq(1), + If(self.wishbone.ack, + NextValue(data, self.wishbone.dat_r), + NextState("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, + 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") + ) + ) + ) + ) + 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)