frontend/wishbone: add efficient wishbone downconvert, improve DRAM access efficiency from CPU on boards with small native data_width.

This commit is contained in:
Florent Kermarrec 2020-01-13 12:58:15 +01:00
parent 34e6c24d72
commit 721c84bad0
1 changed files with 46 additions and 29 deletions

View File

@ -1,4 +1,4 @@
# This file is Copyright (c) 2016-2018 Florent Kermarrec <florent@enjoy-digital.fr> # This file is Copyright (c) 2016-2020 Florent Kermarrec <florent@enjoy-digital.fr>
# License: BSD # License: BSD
"""Wishbone frontend for LiteDRAM""" """Wishbone frontend for LiteDRAM"""
@ -12,52 +12,69 @@ from litex.soc.interconnect import stream
class LiteDRAMWishbone2Native(Module): class LiteDRAMWishbone2Native(Module):
def __init__(self, wishbone, port, base_address=0x00000000): def __init__(self, wishbone, port, base_address=0x00000000):
assert len(wishbone.dat_w) == len(port.wdata.data) wishbone_data_width = len(wishbone.dat_w)
port_data_width = len(port.wdata.data)
assert wishbone_data_width >= port_data_width
# # # # # #
adr_offset = base_address >> log2_int(port.data_width//8) adr_offset = base_address >> log2_int(port.data_width//8)
# Write data buffer------------------------------------------------------------------------- # Write Datapath ---------------------------------------------------------------------------
wdata_buffer = stream.Buffer([("data", port.data_width), ("we", port.data_width//8)]) wdata_converter = stream.StrideConverter(
self.submodules += wdata_buffer [("data", wishbone_data_width), ("we", wishbone_data_width//8)],
[("data", port_data_width), ("we", port_data_width//8)],
)
self.submodules += wdata_converter
self.comb += [
wdata_converter.sink.valid.eq(wishbone.cyc & wishbone.stb & wishbone.we),
wdata_converter.sink.data.eq(wishbone.dat_w),
wdata_converter.sink.we.eq(wishbone.sel),
wdata_converter.source.connect(port.wdata)
]
# Read Datapath ----------------------------------------------------------------------------
rdata_converter = stream.StrideConverter(
[("data", port_data_width)],
[("data", wishbone_data_width)],
)
self.submodules += rdata_converter
self.comb += [
port.rdata.connect(rdata_converter.sink),
rdata_converter.source.ready.eq(1),
wishbone.dat_r.eq(rdata_converter.source.data),
]
# Control ---------------------------------------------------------------------------------- # Control ----------------------------------------------------------------------------------
ratio = wishbone_data_width//port_data_width
count = Signal(max=max(ratio, 2))
self.submodules.fsm = fsm = FSM(reset_state="CMD") self.submodules.fsm = fsm = FSM(reset_state="CMD")
fsm.act("CMD", fsm.act("CMD",
port.cmd.valid.eq(wishbone.cyc & wishbone.stb), port.cmd.valid.eq(wishbone.cyc & wishbone.stb),
port.cmd.we.eq(wishbone.we), port.cmd.we.eq(wishbone.we),
port.cmd.addr.eq(wishbone.adr*ratio + count - adr_offset),
If(port.cmd.valid & port.cmd.ready, If(port.cmd.valid & port.cmd.ready,
If(wishbone.we, NextValue(count, count + 1),
NextState("WRITE") If(count == (ratio - 1),
).Else( If(wishbone.we,
NextState("READ") NextValue(count, 0),
NextState("WAIT-WRITE")
).Else(
NextValue(count, 0),
NextState("WAIT-READ")
)
) )
) )
) )
fsm.act("WRITE", fsm.act("WAIT-WRITE",
wdata_buffer.sink.valid.eq(1), If(wdata_converter.sink.ready,
If(wdata_buffer.sink.ready,
wishbone.ack.eq(1), wishbone.ack.eq(1),
NextState("CMD") NextState("CMD")
) )
) )
fsm.act("READ", fsm.act("WAIT-READ",
port.rdata.ready.eq(1), If(rdata_converter.source.valid,
If(port.rdata.valid, wishbone.ack.eq(1),
wishbone.ack.eq(1), NextState("CMD")
NextState("CMD")
) )
) )
# Datapath ---------------------------------------------------------------------------------
self.comb += [
# Cmd
port.cmd.addr.eq(wishbone.adr - adr_offset),
# Write
wdata_buffer.sink.data.eq(wishbone.dat_w),
wdata_buffer.sink.we.eq(wishbone.sel),
wdata_buffer.source.connect(port.wdata),
# Read
wishbone.dat_r.eq(port.rdata.data),
]