interconnect/wishbonebridge: refresh/simplify.
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Tue, 12 May 2020 10:53:01 +0000 (12:53 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Tue, 12 May 2020 11:40:28 +0000 (13:40 +0200)
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

index 00ec4a0cea3adfa39f85143c7a1a5d08859be082..153a94397a0f19f29db25988738a199c51df5e4a 100644 (file)
-# 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)