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:
parent
c136113a9b
commit
873d95e517
|
@ -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
|
# License: BSD
|
||||||
|
|
||||||
|
from math import log2
|
||||||
|
|
||||||
from migen import *
|
from migen import *
|
||||||
|
|
||||||
from migen.genlib.misc import chooser, WaitTimer
|
from migen.genlib.misc import WaitTimer
|
||||||
from migen.genlib.record import Record
|
|
||||||
from migen.genlib.fsm import FSM, NextState
|
|
||||||
|
|
||||||
from litex.soc.interconnect import wishbone
|
from litex.soc.interconnect import wishbone
|
||||||
from litex.soc.interconnect import stream
|
from litex.soc.interconnect import stream
|
||||||
|
|
||||||
|
# Wishbone Streaming Bridge ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
CMD_WRITE = 0x01
|
||||||
|
CMD_READ = 0x02
|
||||||
|
|
||||||
class WishboneStreamingBridge(Module):
|
class WishboneStreamingBridge(Module):
|
||||||
cmds = {
|
def __init__(self, phy, clk_freq, data_width=32, address_width=32):
|
||||||
"write": 0x01,
|
|
||||||
"read": 0x02
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, phy, clk_freq):
|
|
||||||
self.wishbone = wishbone.Interface()
|
self.wishbone = wishbone.Interface()
|
||||||
|
self.comb += phy.source.ready.eq(1) # Always accept incoming stream.
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
byte_counter = Signal(3, reset_less=True)
|
cmd = Signal(8, reset_less=True)
|
||||||
byte_counter_reset = Signal()
|
length = Signal(8, reset_less=True)
|
||||||
byte_counter_ce = Signal()
|
address = Signal(address_width, reset_less=True)
|
||||||
self.sync += \
|
data = Signal(data_width, reset_less=True)
|
||||||
If(byte_counter_reset,
|
bytes_count = Signal(int(log2(data_width//8)), reset_less=True)
|
||||||
byte_counter.eq(0)
|
words_count = Signal(8, reset_less=True)
|
||||||
).Elif(byte_counter_ce,
|
|
||||||
byte_counter.eq(byte_counter + 1)
|
|
||||||
)
|
|
||||||
|
|
||||||
word_counter = Signal(3, reset_less=True)
|
bytes_count_done = (bytes_count == (data_width//8 - 1))
|
||||||
word_counter_reset = Signal()
|
words_count_done = (words_count == (length - 1))
|
||||||
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)
|
fsm = ResetInserter()(FSM(reset_state="RECEIVE-CMD"))
|
||||||
cmd_ce = Signal()
|
timer = WaitTimer(int(100e-3*clk_freq))
|
||||||
|
self.comb += timer.wait.eq(~fsm.ongoing("RECEIVE-CMD"))
|
||||||
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))
|
|
||||||
self.submodules += fsm, timer
|
self.submodules += fsm, timer
|
||||||
self.comb += [
|
self.comb += fsm.reset.eq(timer.done)
|
||||||
fsm.reset.eq(timer.done),
|
fsm.act("RECEIVE-CMD",
|
||||||
phy.source.ready.eq(1)
|
NextValue(bytes_count, 0),
|
||||||
]
|
NextValue(words_count, 0),
|
||||||
fsm.act("IDLE",
|
|
||||||
If(phy.source.valid,
|
If(phy.source.valid,
|
||||||
cmd_ce.eq(1),
|
NextValue(cmd, phy.source.data),
|
||||||
If((phy.source.data == self.cmds["write"]) |
|
NextState("RECEIVE-LENGTH")
|
||||||
(phy.source.data == self.cmds["read"]),
|
|
||||||
NextState("RECEIVE_LENGTH")
|
|
||||||
),
|
|
||||||
byte_counter_reset.eq(1),
|
|
||||||
word_counter_reset.eq(1)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
fsm.act("RECEIVE_LENGTH",
|
fsm.act("RECEIVE-LENGTH",
|
||||||
If(phy.source.valid,
|
If(phy.source.valid,
|
||||||
length_ce.eq(1),
|
NextValue(length, phy.source.data),
|
||||||
NextState("RECEIVE_ADDRESS")
|
NextState("RECEIVE-ADDRESS")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
fsm.act("RECEIVE_ADDRESS",
|
fsm.act("RECEIVE-ADDRESS",
|
||||||
If(phy.source.valid,
|
If(phy.source.valid,
|
||||||
address_ce.eq(1),
|
NextValue(address, Cat(phy.source.data, address)),
|
||||||
byte_counter_ce.eq(1),
|
NextValue(bytes_count, bytes_count + 1),
|
||||||
If(byte_counter == 3,
|
If(bytes_count_done,
|
||||||
If(cmd == self.cmds["write"],
|
If(cmd == CMD_WRITE,
|
||||||
NextState("RECEIVE_DATA")
|
NextState("RECEIVE-DATA")
|
||||||
).Elif(cmd == self.cmds["read"],
|
).Elif(cmd == CMD_READ,
|
||||||
NextState("READ_DATA")
|
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")
|
|
||||||
).Else(
|
).Else(
|
||||||
NextState("READ_DATA"),
|
NextState("RECEIVE-CMD")
|
||||||
byte_counter_reset.eq(1)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
fsm.act("RECEIVE-DATA",
|
||||||
self.comb += timer.wait.eq(~fsm.ongoing("IDLE"))
|
If(phy.source.valid,
|
||||||
|
NextValue(data, Cat(phy.source.data, data)),
|
||||||
self.comb += phy.sink.last.eq((byte_counter == 3) & (word_counter == length - 1))
|
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"):
|
if hasattr(phy.sink, "length"):
|
||||||
self.comb += phy.sink.length.eq(4*length)
|
self.comb += phy.sink.length.eq((data_width//8)*length)
|
||||||
|
|
Loading…
Reference in New Issue