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 # 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)
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 = Signal(8, reset_less=True)
cmd_ce = Signal()
length = Signal(8, reset_less=True) length = Signal(8, reset_less=True)
length_ce = Signal() 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) bytes_count_done = (bytes_count == (data_width//8 - 1))
address_ce = Signal() words_count_done = (words_count == (length - 1))
data = Signal(32, reset_less=True) fsm = ResetInserter()(FSM(reset_state="RECEIVE-CMD"))
rx_data_ce = Signal() timer = WaitTimer(int(100e-3*clk_freq))
tx_data_ce = Signal() self.comb += timer.wait.eq(~fsm.ongoing("RECEIVE-CMD"))
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")
), ).Else(
byte_counter_reset.eq(1), NextState("RECEIVE-CMD")
) )
) )
) )
fsm.act("RECEIVE_DATA", )
fsm.act("RECEIVE-DATA",
If(phy.source.valid, If(phy.source.valid,
rx_data_ce.eq(1), NextValue(data, Cat(phy.source.data, data)),
byte_counter_ce.eq(1), NextValue(bytes_count, bytes_count + 1),
If(byte_counter == 3, If(bytes_count_done,
NextState("WRITE_DATA"), NextState("WRITE-DATA")
byte_counter_reset.eq(1)
) )
) )
) )
self.comb += [ self.comb += [
self.wishbone.adr.eq(address + word_counter), self.wishbone.adr.eq(address),
self.wishbone.dat_w.eq(data), 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.stb.eq(1),
self.wishbone.we.eq(1), self.wishbone.we.eq(1),
self.wishbone.cyc.eq(1), self.wishbone.cyc.eq(1),
If(self.wishbone.ack, If(self.wishbone.ack,
word_counter_ce.eq(1), NextValue(words_count, words_count + 1),
If(word_counter == (length-1), NextValue(address, address + 1),
NextState("IDLE") If(words_count_done,
NextState("RECEIVE-CMD")
).Else( ).Else(
NextState("RECEIVE_DATA") NextState("RECEIVE-DATA")
) )
) )
) )
fsm.act("READ_DATA", fsm.act("READ-DATA",
self.wishbone.stb.eq(1), self.wishbone.stb.eq(1),
self.wishbone.we.eq(0), self.wishbone.we.eq(0),
self.wishbone.cyc.eq(1), self.wishbone.cyc.eq(1),
If(self.wishbone.ack, If(self.wishbone.ack,
tx_data_ce.eq(1), NextValue(data, self.wishbone.dat_r),
NextState("SEND_DATA") NextState("SEND-DATA")
) )
) )
self.comb += \ cases = {}
chooser(data, byte_counter, phy.sink.data, n=4, reverse=True) for i, n in enumerate(reversed(range(data_width//8))):
fsm.act("SEND_DATA", cases[i] = phy.sink.data.eq(data[8*n:])
self.comb += Case(bytes_count, cases)
fsm.act("SEND-DATA",
phy.sink.valid.eq(1), phy.sink.valid.eq(1),
If(phy.sink.ready, If(phy.sink.ready,
byte_counter_ce.eq(1), NextValue(bytes_count, bytes_count + 1),
If(byte_counter == 3, If(bytes_count_done,
word_counter_ce.eq(1), NextValue(words_count, words_count + 1),
If(word_counter == (length-1), NextValue(address, address + 1),
NextState("IDLE") If(words_count_done,
NextState("RECEIVE-CMD")
).Else( ).Else(
NextState("READ_DATA"), NextState("READ-DATA")
byte_counter_reset.eq(1)
) )
) )
) )
) )
self.comb += phy.sink.last.eq(bytes_count_done & words_count_done)
self.comb += timer.wait.eq(~fsm.ongoing("IDLE"))
self.comb += phy.sink.last.eq((byte_counter == 3) & (word_counter == length - 1))
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)