litex/misoclib/mem/litesata/phy/datapath.py

164 lines
4.7 KiB
Python

from misoclib.mem.litesata.common import *
class LiteSATAPHYDatapathRX(Module):
def __init__(self):
self.sink = sink = Sink(phy_description(16))
self.source = source = Source(phy_description(32))
###
# width convertion (16 to 32) and byte alignment
byte_alignment = Signal()
last_charisk = Signal(2)
last_data = Signal(16)
self.sync.sata_rx += \
If(sink.stb & sink.ack,
If(sink.charisk != 0,
byte_alignment.eq(sink.charisk[1])
),
last_charisk.eq(sink.charisk),
last_data.eq(sink.data)
)
converter = Converter(phy_description(16), phy_description(32), reverse=False)
converter = InsertReset(RenameClockDomains(converter, "sata_rx"))
self.submodules += converter
self.comb += [
converter.sink.stb.eq(sink.stb),
If(byte_alignment,
converter.sink.charisk.eq(Cat(last_charisk[1], sink.charisk[0])),
converter.sink.data.eq(Cat(last_data[8:], sink.data[:8]))
).Else(
converter.sink.charisk.eq(sink.charisk),
converter.sink.data.eq(sink.data)
),
sink.ack.eq(converter.sink.ack),
converter.reset.eq(converter.source.charisk[2:] != 0)
]
# clock domain crossing
# (sata_gen3) 300MHz sata_rx clk to sys_clk
# (sata_gen2) 150MHz sata_rx clk to sys_clk
# (sata_gen1) 75MHz sata_rx clk to sys_clk
# requirements:
# due to the convertion ratio of 2, sys_clk need to be > sata_rx/2
# source destination is always able to accept data (ack always 1)
fifo = AsyncFIFO(phy_description(32), 4)
fifo = RenameClockDomains(fifo, {"write": "sata_rx", "read": "sys"})
self.submodules += fifo
self.comb += [
Record.connect(converter.source, fifo.sink),
Record.connect(fifo.source, source)
]
class LiteSATAPHYDatapathTX(Module):
def __init__(self):
self.sink = sink = Sink(phy_description(32))
self.source = source = Source(phy_description(16))
###
# clock domain crossing
# (sata_gen3) sys_clk to 300MHz sata_tx clk
# (sata_gen2) sys_clk to 150MHz sata_tx clk
# (sata_gen1) sys_clk to 75MHz sata_tx clk
# requirements:
# source destination is always able to accept data (ack always 1)
fifo = AsyncFIFO(phy_description(32), 4)
fifo = RenameClockDomains(fifo, {"write": "sys", "read": "sata_tx"})
self.submodules += fifo
self.comb += Record.connect(sink, fifo.sink)
# width convertion (32 to 16)
converter = Converter(phy_description(32), phy_description(16), reverse=False)
converter = RenameClockDomains(converter, "sata_tx")
self.submodules += converter
self.comb += [
Record.connect(fifo.source, converter.sink),
Record.connect(converter.source, source)
]
class LiteSATAPHYAlignInserter(Module):
def __init__(self, ctrl):
self.sink = sink = Sink(phy_description(32))
self.source = source = Source(phy_description(32))
###
# send 2 ALIGN every 256 DWORDs
# used for clock compensation between
# HOST and device
cnt = Signal(8)
send = Signal()
self.sync += \
If(~ctrl.ready,
cnt.eq(0)
).Elif(source.stb & source.ack,
cnt.eq(cnt+1)
)
self.comb += [
send.eq(cnt < 2),
If(send,
source.stb.eq(1),
source.charisk.eq(0b0001),
source.data.eq(primitives["ALIGN"]),
sink.ack.eq(0)
).Else(
source.stb.eq(sink.stb),
source.data.eq(sink.data),
source.charisk.eq(sink.charisk),
sink.ack.eq(source.ack)
)
]
class LiteSATAPHYAlignRemover(Module):
def __init__(self):
self.sink = sink = Sink(phy_description(32))
self.source = source = Source(phy_description(32))
###
charisk_match = sink.charisk == 0b0001
data_match = sink.data == primitives["ALIGN"]
self.comb += \
If(sink.stb & charisk_match & data_match,
sink.ack.eq(1),
).Else(
Record.connect(sink, source)
)
class LiteSATAPHYDatapath(Module):
def __init__(self, trx, ctrl):
self.sink = sink = Sink(phy_description(32))
self.source = source = Source(phy_description(32))
###
# TX path
align_inserter = LiteSATAPHYAlignInserter(ctrl)
mux = Multiplexer(phy_description(32), 2)
tx = LiteSATAPHYDatapathTX()
self.submodules += align_inserter, mux, tx
self.comb += [
mux.sel.eq(ctrl.ready),
Record.connect(sink, align_inserter.sink),
Record.connect(ctrl.source, mux.sink0),
Record.connect(align_inserter.source, mux.sink1),
Record.connect(mux.source, tx.sink),
Record.connect(tx.source, trx.sink)
]
# RX path
rx = LiteSATAPHYDatapathRX()
demux = Demultiplexer(phy_description(32), 2)
align_remover = LiteSATAPHYAlignRemover()
self.submodules += rx, demux, align_remover
self.comb += [
demux.sel.eq(ctrl.ready),
Record.connect(trx.source, rx.sink),
Record.connect(rx.source, demux.sink),
Record.connect(demux.source0, ctrl.sink),
Record.connect(demux.source1, align_remover.sink),
Record.connect(align_remover.source, source)
]