2014-12-14 04:45:26 -05:00
|
|
|
from lib.sata.common import *
|
2014-09-27 09:34:28 -04:00
|
|
|
|
2014-12-18 12:02:35 -05:00
|
|
|
from migen.genlib.misc import chooser
|
2014-12-19 10:48:22 -05:00
|
|
|
from migen.flow.plumbing import Multiplexer, Demultiplexer
|
2014-12-19 11:13:03 -05:00
|
|
|
from migen.actorlib.structuring import Converter
|
2014-12-18 12:02:35 -05:00
|
|
|
|
|
|
|
class SATAPHYDatapathRX(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-09-29 12:25:24 -04:00
|
|
|
# bytes alignment
|
2014-10-24 13:24:05 -04:00
|
|
|
|
2014-09-29 12:25:24 -04:00
|
|
|
# shift register
|
|
|
|
data_sr = Signal(32+8)
|
|
|
|
charisk_sr = Signal(4+1)
|
|
|
|
data_sr_d = Signal(32+8)
|
|
|
|
charisk_sr_d = Signal(4+1)
|
|
|
|
self.comb += [
|
2014-12-17 14:57:37 -05:00
|
|
|
data_sr.eq(Cat(data_sr_d[16:], self.sink.data)),
|
|
|
|
charisk_sr.eq(Cat(charisk_sr_d[2:], self.sink.charisk))
|
2014-09-29 12:25:24 -04:00
|
|
|
]
|
2014-09-27 09:34:28 -04:00
|
|
|
self.sync.sata_rx += [
|
2014-09-29 12:25:24 -04:00
|
|
|
data_sr_d.eq(data_sr),
|
|
|
|
charisk_sr_d.eq(charisk_sr)
|
|
|
|
]
|
|
|
|
|
|
|
|
# alignment
|
|
|
|
alignment = Signal()
|
|
|
|
valid = Signal()
|
|
|
|
self.sync.sata_rx += [
|
2014-10-24 13:24:05 -04:00
|
|
|
If(self.sink.charisk !=0,
|
|
|
|
alignment.eq(self.sink.charisk[1]),
|
2014-09-29 12:25:24 -04:00
|
|
|
valid.eq(0)
|
2014-09-29 07:02:11 -04:00
|
|
|
).Else(
|
2014-09-29 12:25:24 -04:00
|
|
|
valid.eq(~valid)
|
2014-09-29 07:02:11 -04:00
|
|
|
)
|
2014-09-27 09:34:28 -04:00
|
|
|
]
|
2014-09-29 07:02:11 -04:00
|
|
|
|
2014-09-29 12:25:24 -04:00
|
|
|
# 16 to 32
|
|
|
|
data = Signal(32)
|
|
|
|
charisk = Signal(4)
|
2014-09-27 09:34:28 -04:00
|
|
|
self.comb += [
|
2014-12-17 14:57:37 -05:00
|
|
|
If(alignment,
|
2014-09-29 12:25:24 -04:00
|
|
|
data.eq(data_sr[0:32]),
|
|
|
|
charisk.eq(charisk_sr[0:4])
|
|
|
|
).Else(
|
|
|
|
data.eq(data_sr[8:40]),
|
|
|
|
charisk.eq(charisk_sr[1:5])
|
|
|
|
)
|
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-09-29 12:25:24 -04:00
|
|
|
fifo.sink.stb.eq(valid),
|
2014-10-24 13:24:05 -04:00
|
|
|
fifo.sink.data.eq(data),
|
|
|
|
fifo.sink.charisk.eq(charisk),
|
2014-12-19 11:13:03 -05:00
|
|
|
self.sink.ack.eq(fifo.sink.ack)
|
2014-09-27 09:34:28 -04:00
|
|
|
]
|
2014-09-29 12:25:24 -04:00
|
|
|
self.comb += Record.connect(fifo.source, self.source)
|
2014-09-27 09:34:28 -04:00
|
|
|
|
2014-12-18 12:02:35 -05:00
|
|
|
class SATAPHYDatapathTX(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:13:03 -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)
|
|
|
|
self.converter = Converter(phy_description(32), phy_description(16), reverse=True)
|
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
|
|
|
]
|
|
|
|
|
2014-12-19 10:48:22 -05:00
|
|
|
class SATAPHYAlignInserter(Module):
|
|
|
|
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)
|
|
|
|
)
|
|
|
|
]
|
|
|
|
|
|
|
|
class SATAPHYAlignRemover(Module):
|
|
|
|
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)
|
|
|
|
)
|
|
|
|
|
2014-12-18 12:02:35 -05:00
|
|
|
class SATAPHYDatapath(Module):
|
|
|
|
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
|
|
|
|
self.align_inserter = SATAPHYAlignInserter(ctrl)
|
|
|
|
self.mux = Multiplexer(phy_description(32), 2)
|
|
|
|
self.tx = SATAPHYDatapathTX()
|
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
|
|
|
|
self.rx = SATAPHYDatapathRX()
|
|
|
|
self.demux = Demultiplexer(phy_description(32), 2)
|
|
|
|
self.align_remover = SATAPHYAlignRemover()
|
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
|
|
|
]
|