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()
This commit is contained in:
Florent Kermarrec 2020-05-12 12:53:01 +02:00
parent c136113a9b
commit 873d95e517
1 changed files with 97 additions and 137 deletions

View File

@ -1,167 +1,127 @@
# 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 ------------------------------------------------------------------------
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)