2015-01-16 17:52:41 -05:00
|
|
|
from litesata.common import *
|
2014-09-27 09:34:28 -04:00
|
|
|
|
2015-01-16 17:52:41 -05:00
|
|
|
class LiteSATAPHYDatapathRX(Module):
|
2014-09-29 12:25:24 -04:00
|
|
|
def __init__(self):
|
2014-11-11 08:54:54 -05:00
|
|
|
self.sink = Sink(phy_description(16))
|
|
|
|
self.source = Source(phy_description(32))
|
2014-09-27 09:34:28 -04:00
|
|
|
|
|
|
|
###
|
|
|
|
|
2014-12-19 11:27:44 -05:00
|
|
|
# width convertion (16 to 32) and byte alignment
|
2014-12-19 14:16:37 -05:00
|
|
|
byte_alignment = Signal()
|
2014-12-19 11:27:44 -05:00
|
|
|
last_charisk = Signal(2)
|
|
|
|
last_data = Signal(16)
|
2014-12-19 14:16:37 -05:00
|
|
|
self.sync.sata_rx += \
|
2014-12-19 11:27:44 -05:00
|
|
|
If(self.sink.stb & self.sink.ack,
|
|
|
|
If(self.sink.charisk != 0,
|
2014-12-19 14:16:37 -05:00
|
|
|
byte_alignment.eq(self.sink.charisk[1])
|
2014-12-19 11:27:44 -05:00
|
|
|
),
|
2014-12-19 14:16:37 -05:00
|
|
|
last_charisk.eq(self.sink.charisk),
|
2014-12-19 11:27:44 -05:00
|
|
|
last_data.eq(self.sink.data)
|
2014-09-29 07:02:11 -04:00
|
|
|
)
|
2014-12-19 14:16:37 -05:00
|
|
|
converter = Converter(phy_description(16), phy_description(32), reverse=False)
|
|
|
|
self.converter = InsertReset(RenameClockDomains(converter, "sata_rx"))
|
2014-09-27 09:34:28 -04:00
|
|
|
self.comb += [
|
2014-12-19 11:27:44 -05:00
|
|
|
self.converter.sink.stb.eq(self.sink.stb),
|
2014-12-19 14:16:37 -05:00
|
|
|
If(byte_alignment,
|
|
|
|
self.converter.sink.charisk.eq(Cat(last_charisk[1], self.sink.charisk[0])),
|
|
|
|
self.converter.sink.data.eq(Cat(last_data[8:], self.sink.data[:8]))
|
2014-09-29 12:25:24 -04:00
|
|
|
).Else(
|
2014-12-19 14:16:37 -05:00
|
|
|
self.converter.sink.charisk.eq(self.sink.charisk),
|
2014-12-19 11:27:44 -05:00
|
|
|
self.converter.sink.data.eq(self.sink.data)
|
|
|
|
),
|
2014-12-19 14:16:37 -05:00
|
|
|
self.sink.ack.eq(self.converter.sink.ack),
|
|
|
|
self.converter.reset.eq(self.converter.source.charisk[2:] != 0)
|
2014-09-27 09:34:28 -04:00
|
|
|
]
|
|
|
|
|
2014-09-29 12:25:24 -04:00
|
|
|
# clock domain crossing
|
|
|
|
# (SATA3) 300MHz sata_rx clk to sys_clk
|
|
|
|
# (SATA2) 150MHz sata_rx clk to sys_clk
|
|
|
|
# (SATA1) 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)
|
2014-12-17 06:50:02 -05:00
|
|
|
fifo = AsyncFIFO(phy_description(32), 4)
|
2014-12-18 19:35:18 -05:00
|
|
|
self.fifo = RenameClockDomains(fifo, {"write": "sata_rx", "read": "sys"})
|
2014-09-27 09:34:28 -04:00
|
|
|
self.comb += [
|
2014-12-19 11:27:44 -05:00
|
|
|
Record.connect(self.converter.source, fifo.sink),
|
|
|
|
Record.connect(fifo.source, self.source)
|
2014-09-27 09:34:28 -04:00
|
|
|
]
|
|
|
|
|
2015-01-16 17:52:41 -05:00
|
|
|
class LiteSATAPHYDatapathTX(Module):
|
2014-09-27 09:34:28 -04:00
|
|
|
def __init__(self):
|
2014-11-11 08:54:54 -05:00
|
|
|
self.sink = Sink(phy_description(32))
|
|
|
|
self.source = Source(phy_description(16))
|
2014-09-27 09:34:28 -04:00
|
|
|
|
|
|
|
###
|
|
|
|
|
2014-09-29 12:25:24 -04:00
|
|
|
# clock domain crossing
|
|
|
|
# (SATA3) sys_clk to 300MHz sata_tx clk
|
|
|
|
# (SATA2) sys_clk to 150MHz sata_tx clk
|
|
|
|
# (SATA1) sys_clk to 75MHz sata_tx clk
|
|
|
|
# requirements:
|
|
|
|
# source destination is always able to accept data (ack always 1)
|
2014-12-17 06:50:02 -05:00
|
|
|
fifo = AsyncFIFO(phy_description(32), 4)
|
2014-12-18 19:35:18 -05:00
|
|
|
self.fifo = RenameClockDomains(fifo, {"write": "sys", "read": "sata_tx"})
|
2014-12-19 11:27:44 -05:00
|
|
|
self.comb += Record.connect(self.sink, fifo.sink)
|
2014-09-29 12:25:24 -04:00
|
|
|
|
2014-12-19 11:13:03 -05:00
|
|
|
# width convertion (32 to 16)
|
2014-12-19 14:16:37 -05:00
|
|
|
converter = Converter(phy_description(32), phy_description(16), reverse=False)
|
|
|
|
self.converter = RenameClockDomains(converter, "sata_tx")
|
2014-09-27 09:34:28 -04:00
|
|
|
self.comb += [
|
2014-12-19 11:13:03 -05:00
|
|
|
Record.connect(self.fifo.source, self.converter.sink),
|
|
|
|
Record.connect(self.converter.source, self.source)
|
2014-09-29 12:25:24 -04:00
|
|
|
]
|
|
|
|
|
2015-01-16 17:52:41 -05:00
|
|
|
class LiteSATAPHYAlignInserter(Module):
|
2014-12-19 10:48:22 -05:00
|
|
|
def __init__(self, ctrl):
|
|
|
|
self.sink = sink = Sink(phy_description(32))
|
|
|
|
self.source = source = Source(phy_description(32))
|
2014-12-19 11:13:03 -05:00
|
|
|
|
2014-12-19 10:48:22 -05:00
|
|
|
###
|
2014-12-19 11:13:03 -05:00
|
|
|
|
2014-12-19 10:48:22 -05:00
|
|
|
# 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)
|
|
|
|
)
|
|
|
|
]
|
|
|
|
|
2015-01-16 17:52:41 -05:00
|
|
|
class LiteSATAPHYAlignRemover(Module):
|
2014-12-19 10:48:22 -05:00
|
|
|
def __init__(self):
|
|
|
|
self.sink = sink = Sink(phy_description(32))
|
|
|
|
self.source = source = Source(phy_description(32))
|
2014-12-19 11:13:03 -05:00
|
|
|
|
2014-12-19 10:48:22 -05:00
|
|
|
###
|
2014-12-19 11:13:03 -05:00
|
|
|
|
2014-12-19 10:48:22 -05:00
|
|
|
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)
|
|
|
|
)
|
|
|
|
|
2015-01-16 17:52:41 -05:00
|
|
|
class LiteSATAPHYDatapath(Module):
|
2014-12-18 12:02:35 -05:00
|
|
|
def __init__(self, trx, ctrl):
|
2014-11-11 08:54:54 -05:00
|
|
|
self.sink = Sink(phy_description(32))
|
|
|
|
self.source = Source(phy_description(32))
|
2014-09-27 09:34:28 -04:00
|
|
|
|
2014-09-29 12:25:24 -04:00
|
|
|
###
|
|
|
|
|
2014-12-19 10:48:22 -05:00
|
|
|
# TX path
|
2015-01-16 17:52:41 -05:00
|
|
|
self.align_inserter = LiteSATAPHYAlignInserter(ctrl)
|
2014-12-19 10:48:22 -05:00
|
|
|
self.mux = Multiplexer(phy_description(32), 2)
|
2015-01-16 17:52:41 -05:00
|
|
|
self.tx = LiteSATAPHYDatapathTX()
|
2014-09-27 09:34:28 -04:00
|
|
|
self.comb += [
|
2014-12-19 10:48:22 -05:00
|
|
|
self.mux.sel.eq(ctrl.ready),
|
|
|
|
Record.connect(self.sink, self.align_inserter.sink),
|
|
|
|
Record.connect(ctrl.source, self.mux.sink0),
|
|
|
|
Record.connect(self.align_inserter.source, self.mux.sink1),
|
|
|
|
Record.connect(self.mux.source, self.tx.sink),
|
|
|
|
Record.connect(self.tx.source, trx.sink)
|
2014-09-27 09:34:28 -04:00
|
|
|
]
|
|
|
|
|
2014-12-19 10:48:22 -05:00
|
|
|
# RX path
|
2015-01-16 17:52:41 -05:00
|
|
|
self.rx = LiteSATAPHYDatapathRX()
|
2014-12-19 10:48:22 -05:00
|
|
|
self.demux = Demultiplexer(phy_description(32), 2)
|
2015-01-16 17:52:41 -05:00
|
|
|
self.align_remover = LiteSATAPHYAlignRemover()
|
2014-09-27 09:34:28 -04:00
|
|
|
self.comb += [
|
2014-12-19 10:48:22 -05:00
|
|
|
self.demux.sel.eq(ctrl.ready),
|
|
|
|
Record.connect(trx.source, self.rx.sink),
|
|
|
|
Record.connect(self.rx.source, self.demux.sink),
|
|
|
|
Record.connect(self.demux.source0, ctrl.sink),
|
|
|
|
Record.connect(self.demux.source1, self.align_remover.sink),
|
|
|
|
Record.connect(self.align_remover.source, self.source)
|
2014-09-27 09:34:28 -04:00
|
|
|
]
|