from migen.fhdl.std import *
-from migen.flow.actor import Sink, Source
from lib.sata.k7sataphy.std import *
from lib.sata.k7sataphy.gtx import K7SATAPHYGTX
from lib.sata.k7sataphy.crg import K7SATAPHYCRG
from lib.sata.k7sataphy.ctrl import K7SATAPHYHostCtrl, K7SATAPHYDeviceCtrl
-from lib.sata.k7sataphy.datapath import K7SATAPHYRXConvert, K7SATAPHYTXConvert
+from lib.sata.k7sataphy.datapath import K7SATAPHYDatapath
class K7SATAPHY(Module):
- def __init__(self, pads, clk_freq, host=True, default_speed="SATA3"):
- self.sink = Sink([("d", 32)])
- self.source = Source([("d", 32)])
-
+ def __init__(self, pads, clk_freq, host=True, default_speed="SATA1"):
# GTX
- gtx = K7SATAPHYGTX(pads, default_speed)
- self.submodules += gtx
+ self.submodules.gtx = K7SATAPHYGTX(pads, default_speed)
# CRG / CTRL
- crg = K7SATAPHYCRG(pads, gtx, clk_freq, default_speed)
+ self.submodules.crg = K7SATAPHYCRG(pads, self.gtx, clk_freq, default_speed)
if host:
- ctrl = K7SATAPHYHostCtrl(gtx, crg, clk_freq)
+ self.submodules.ctrl = K7SATAPHYHostCtrl(self.gtx, self.crg, clk_freq)
else:
- ctrl = K7SATAPHYDeviceCtrl(gtx, crg, clk_freq)
- self.submodules += crg, ctrl
+ self.submodules.ctrl = K7SATAPHYDeviceCtrl(self.gtx, self.crg, clk_freq)
# DATAPATH
- rxconvert = K7SATAPHYRXConvert()
- txconvert = K7SATAPHYTXConvert()
- self.submodules += rxconvert, txconvert
- self.comb += [
- rxconvert.rxdata.eq(gtx.rxdata),
- rxconvert.rxcharisk.eq(gtx.rxcharisk),
-
- gtx.txdata.eq(txconvert.txdata),
- gtx.txcharisk.eq(txconvert.txcharisk)
- ]
-
- self.comb += [
- If(ctrl.ready,
- txconvert.sink.stb.eq(self.sink.stb),
- txconvert.sink.data.eq(self.sink.d),
- txconvert.sink.charisk.eq(0),
- self.sink.ack.eq(txconvert.sink.ack),
- ).Else(
- txconvert.sink.stb.eq(1),
- txconvert.sink.data.eq(ctrl.txdata),
- txconvert.sink.charisk.eq(ctrl.txcharisk)
- ),
- self.source.stb.eq(rxconvert.source.stb),
- self.source.payload.eq(rxconvert.source.data),
- rxconvert.source.ack.eq(1),
- ctrl.rxdata.eq(rxconvert.source.data)
- ]
+ self.submodules.datapath = K7SATAPHYDatapath(self.gtx, self.ctrl)
+ self.sink, self.source = self.datapath.sink, self.datapath.source
class K7SATAPHYReconfig(Module):
def __init__(self, channel_drp, mmcm_drp):
self.speed = Signal(3)
+
###
- speed_r = Signal(3)
- speed_change = Signal()
- self.sync += speed_r.eq(self.speed)
- self.comb += speed_change.eq(self.speed != speed_r)
drp_sel = Signal()
drp = DRPBus()
).Else(
drp.connect(channel_drp)
)
+ # Todo
class K7SATAPHYCRG(Module):
def __init__(self, pads, gtx, clk_freq, default_speed):
# CPLL
# (SATA3) 150MHz / VCO @ 3GHz / Line rate @ 6Gbps
- # (SATA2 & SATA1) VCO still @ 3 GHz, Line rate is decreased with output divivers.
+ # (SATA2 & SATA1) VCO still @ 3 GHz, Line rate is decreased with output dividers.
# When changing rate, reconfiguration of the CPLL over DRP is needed to:
# - update the output divider
# - update the equalizer configuration (specific for each line rate).
]
# RX clocking
- # (SATA3) sata_rx recovered clk @ 300MHz from CPLL RXOUTCLK
- # (SATA2) sata_rx recovered clk @ 150MHz from CPLL RXOUTCLK
- # (SATA1) sata_rx recovered clk @ 150MHz from CPLL RXOUTCLK
+ # (SATA3) sata_rx recovered clk @ 300MHz from GTX RXOUTCLK
+ # (SATA2) sata_rx recovered clk @ 150MHz from GTX RXOUTCLK
+ # (SATA1) sata_rx recovered clk @ 150MHz from GTX RXOUTCLK
self.specials += [
Instance("BUFG", i_I=gtx.rxoutclk, o_O=self.cd_sata_rx.clk),
]
gtx.rxusrclk2.eq(self.cd_sata_rx.clk)
]
- # Bypass TX buffer
- self.comb += [
- gtx.txphdlyreset.eq(0),
- gtx.txphalignen.eq(0),
- gtx.txdlyen.eq(0),
- gtx.txphalign.eq(0),
- gtx.txphinit.eq(0)
- ]
-
- # Bypass RX buffer
- self.comb += [
- gtx.rxphdlyreset.eq(0),
- gtx.rxdlyen.eq(0),
- gtx.rxphalign.eq(0),
- gtx.rxphalignen.eq(0),
- ]
-
# Configuration Reset
- # After configuration, GTX resets have to stay low for at least 500ns
+ # After configuration, GTX's resets have to stay low for at least 500ns
# See AR43482
reset_en = Signal()
clk_period_ns = 1000000000/clk_freq
)
)
+ # Ready
self.comb += self.ready.eq(tx_reset_fsm.ongoing("READY") & rx_reset_fsm.ongoing("READY"))
# Reset PLL
self.rxdata = Signal(32)
- align_timeout = Signal()
align_detect = Signal()
- retry_cnt = Signal(32)
+ align_timeout_cnt = Signal(32)
+ align_timeout = Signal()
+
+ retry_timeout_cnt = Signal(32)
+ retry_timeout = Signal()
+
non_align_cnt = Signal(4)
txcominit = Signal()
If(gtx.rxcominitdet,
NextState("AWAIT_NO_COMINIT")
).Else(
- If(retry_cnt == 0,
+ If(retry_timeout,
NextState("RESET")
)
)
If(gtx.rxcomwakedet,
NextState("AWAIT_NO_COMWAKE")
).Else(
- If(retry_cnt == 0,
+ If(retry_timeout,
NextState("RESET")
)
)
)
fsm.act("AWAIT_ALIGN",
gtx.txelecidle.eq(0),
+ self.txdata.eq(0x4A4A4A4A), #D10.2
+ self.txcharisk.eq(0b0000),
gtx.rxalign.eq(1),
If(align_detect & ~align_timeout,
NextState("SEND_ALIGN")
gtx.txelecidle.eq(0),
self.txdata.eq(ALIGN_VAL),
self.txcharisk.eq(0b0001),
- If(non_align_cnt == 15,
+ If(non_align_cnt == 3,
NextState("READY")
)
)
gtx.txcominit.eq(txcominit & ~txcominit_d),
gtx.txcomwake.eq(txcomwake & ~txcomwake_d),
]
- self.comb += align_detect.eq(self.rxdata == ALIGN_VAL);
- align_timeout_cnt = Signal(16)
+ self.comb += align_detect.eq(self.rxdata == ALIGN_VAL);
self.sync += \
If(fsm.ongoing("RESET"),
align_timeout_cnt.eq(us(873, clk_freq))
self.sync += \
If(fsm.ongoing("RESET") | fsm.ongoing("AWAIT_NO_COMINIT"),
- retry_cnt.eq(us(10000, clk_freq))
+ retry_timeout_cnt.eq(us(10000, clk_freq))
).Elif(fsm.ongoing("AWAIT_COMINIT") | fsm.ongoing("AWAIT_COMWAKE"),
- retry_cnt.eq(retry_cnt-1)
+ retry_timeout_cnt.eq(retry_timeout_cnt-1)
)
+ self.comb += retry_timeout.eq(retry_timeout_cnt == 0)
self.sync += \
If(fsm.ongoing("SEND_ALIGN"),
self.rxdata = Signal(32)
- align_timeout = Signal()
align_detect = Signal()
- retry_cnt = Signal(32)
+ align_timeout = Signal()
+ align_timeout_cnt = Signal(32)
+
+ retry_timeout_cnt = Signal(32)
+ retry_timeout = Signal()
txcominit = Signal()
txcomwake = Signal()
If(gtx.rxcomwakedet,
NextState("AWAIT_NO_COMWAKE")
).Else(
- If(retry_cnt == 0,
+ If(retry_timeout,
NextState("RESET")
)
)
gtx.txcominit.eq(txcominit & ~txcominit_d),
gtx.txcomwake.eq(txcomwake & ~txcomwake),
]
- self.comb += align_detect.eq(self.rxdata == ALIGN_VAL);
- align_timeout_cnt = Signal(16)
+ self.comb += align_detect.eq(self.rxdata == ALIGN_VAL);
self.sync += \
If(fsm.ongoing("RESET"),
align_timeout_cnt.eq(us(55, clk_freq))
self.sync += \
If(fsm.ongoing("RESET"),
- retry_cnt.eq(us(10000, clk_freq))
+ retry_timeout_cnt.eq(us(10000, clk_freq))
).Elif(fsm.ongoing("AWAIT_COMWAKE"),
- retry_cnt.eq(retry_cnt-1)
+ retry_timeout_cnt.eq(retry_timeout_cnt-1)
)
+ self.comb += retry_timeout.eq(retry_timeout_cnt == 0)
from migen.fhdl.std import *
+from migen.genlib.misc import chooser
from migen.actorlib.fifo import AsyncFIFO
-from migen.actorlib.structuring import Converter
from migen.flow.actor import Sink, Source
from lib.sata.k7sataphy.std import *
-class K7SATAPHYRXConvert(Module):
- def __init__(self, dw=16):
- self.rxdata = Signal(dw)
- self.rxcharisk = Signal(dw//8)
-
+class K7SATAPHYDatapathRX(Module):
+ def __init__(self):
+ self.sink = Sink([("data", 16), ("charisk", 2)])
self.source = Source([("data", 32), ("charisk", 4)])
###
- # byte alignment
- rxdata_r = Signal(2*dw)
- rxcharisk_r = Signal((2*dw)//8)
- rxalignment = Signal(dw//8)
- rxvalid = Signal()
+ # bytes alignment
+
+ # 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 += [
+ data_sr.eq(Cat(self.sink.data, data_sr_d)),
+ charisk_sr.eq(Cat(self.sink.charisk, charisk_sr_d))
+ ]
self.sync.sata_rx += [
- rxdata_r.eq(Cat(self.rxdata, rxdata_r[0:dw])),
- rxcharisk_r.eq(Cat(self.rxcharisk, rxcharisk_r[0:dw//8])),
- If(self.rxcharisk != 0,
- rxalignment.eq(self.rxcharisk),
- rxvalid.eq(1)
+ data_sr_d.eq(data_sr),
+ charisk_sr_d.eq(charisk_sr)
+ ]
+
+ # alignment
+ alignment = Signal()
+ valid = Signal()
+ self.sync.sata_rx += [
+ If(self.sink.charisk !=0,
+ alignment.eq(self.sink.charisk[1]),
+ valid.eq(0)
).Else(
- rxvalid.eq(~rxvalid)
+ valid.eq(~valid)
)
]
- rxdata = Signal(2*dw)
- rxcharisk = Signal((2*dw)//8)
- cases = {}
- cases[1<<0] = [
- rxdata.eq(rxdata_r[0:]),
- rxcharisk.eq(rxcharisk_r[0:])
- ]
- for i in range(1, dw//8):
- cases[1<<i] = [
- rxdata.eq(Cat(self.rxdata[8*i:dw], rxdata_r[0:dw+8*i])),
- rxcharisk.eq(Cat(self.rxcharisk[i:dw//8], rxcharisk_r[0:dw//8+i]))
- ]
- self.comb += Case(rxalignment, cases)
-
- # clock domain crossing
- rx_fifo = AsyncFIFO([("data", 32), ("charisk", 4)], 16)
- self.submodules.rx_fifo = RenameClockDomains(rx_fifo, {"write": "sata_rx", "read": "sys"})
+ # 16 to 32
+ data = Signal(32)
+ charisk = Signal(4)
self.comb += [
- rx_fifo.sink.stb.eq(rxvalid),
- rx_fifo.sink.data.eq(rxdata),
- rx_fifo.sink.charisk.eq(rxcharisk),
+ If(~alignment,
+ 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])
+ )
]
- # connect source
+ # 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)
+ fifo = AsyncFIFO([("data", 32), ("charisk", 4)], 16)
+ self.submodules.fifo = RenameClockDomains(fifo, {"write": "sata_rx", "read": "sys"})
self.comb += [
- Record.connect(rx_fifo.source, self.source)
+ fifo.sink.stb.eq(valid),
+ fifo.sink.data.eq(data),
+ fifo.sink.charisk.eq(charisk),
]
+ self.comb += Record.connect(fifo.source, self.source)
-class K7SATAPHYTXConvert(Module):
+class K7SATAPHYDatapathTX(Module):
def __init__(self):
self.sink = Sink([("data", 32), ("charisk", 4)])
+ self.source = Source([("data", 16), ("charisk", 2)])
- self.txdata = Signal(16)
- self.txcharisk = Signal(2)
###
- # convert data widths
- tx_converter = RenameClockDomains(Converter([("raw", 32+4)], [("raw", 16+2)]), "sata_tx")
- self.submodules += tx_converter
+ # 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)
+ fifo = AsyncFIFO([("data", 32), ("charisk", 4)], 16)
+ self.submodules.fifo = RenameClockDomains(fifo, {"write": "sys", "read": "sata_tx"})
+ self.comb += Record.connect(self.sink, fifo.sink)
+
+ # 32 to 16
+ mux = Signal()
+ last = Signal()
self.comb += [
- Cat(self.txdata, self.txcharisk).eq(tx_converter.source.raw),
- tx_converter.source.ack.eq(1),
+ last.eq(mux == 1),
+ self.source.stb.eq(fifo.source.stb),
+ fifo.source.ack.eq(last),
]
+ self.sync.sata_tx += [
+ If(self.source.stb,
+ If(last,
+ mux.eq(0)
+ ).Else(
+ mux.eq(mux + 1)
+ )
+ )
+ ]
+ self.comb += [
+ chooser(fifo.source.data, mux, self.source.data),
+ chooser(fifo.source.charisk, mux, self.source.charisk)
+ ]
+
+class K7SATAPHYDatapath(Module):
+ def __init__(self, gtx, ctrl):
+ self.sink = Sink([("d", 32)])
+ self.source = Source([("d", 32)])
- # clock domain crossing
- tx_fifo = AsyncFIFO([("raw", 36)], 16)
- self.submodules.tx_fifo = RenameClockDomains(tx_fifo, {"write": "sys", "read": "sata_tx"})
+ ###
+
+ # change data width & cross domain crossing
+ rx = K7SATAPHYDatapathRX()
+ tx = K7SATAPHYDatapathTX()
+ self.submodules += rx, tx
self.comb += [
- tx_fifo.source.connect(tx_converter.sink),
- self.tx_fifo.sink.stb.eq(1),
+ rx.sink.data.eq(gtx.rxdata),
+ rx.sink.charisk.eq(gtx.rxcharisk),
+
+ gtx.txdata.eq(tx.source.data),
+ gtx.txcharisk.eq(tx.source.charisk),
]
- # rearrange data
+ # user / ctrl mux
self.comb += [
- self.tx_fifo.sink.stb.eq(self.sink.stb),
- self.tx_fifo.sink.raw.eq(Cat(self.sink.data[0:16], self.sink.charisk[0:2],
- self.sink.data[16:32], self.sink.charisk[2:4])),
- self.sink.ack.eq(self.tx_fifo.sink.ack),
+ # user
+ If(ctrl.ready,
+ tx.sink.stb.eq(self.sink.stb),
+ tx.sink.data.eq(self.sink.d),
+ tx.sink.charisk.eq(0),
+ self.sink.ack.eq(tx.sink.ack),
+
+ self.source.stb.eq(rx.source.stb),
+ self.source.d.eq(rx.source.data),
+ rx.source.ack.eq(1),
+ # ctrl
+ ).Else(
+ tx.sink.stb.eq(1),
+ tx.sink.data.eq(ctrl.txdata),
+ tx.sink.charisk.eq(ctrl.txcharisk),
+
+ ctrl.rxdata.eq(rx.source.data),
+ rx.source.ack.eq(1),
+ )
]
from migen.fhdl.std import *
from migen.genlib.cdc import *
-from migen.actorlib.fifo import AsyncFIFO
-from migen.actorlib.structuring import Converter
-from migen.flow.actor import Sink, Source
from lib.sata.k7sataphy.std import *
self.rxbyterealign = Signal()
self.rxcommadet = Signal()
+ # Bypass TX buffer
+ self.comb += [
+ self.txphdlyreset.eq(0),
+ self.txphalignen.eq(0),
+ self.txdlyen.eq(0),
+ self.txphalign.eq(0),
+ self.txphinit.eq(0)
+ ]
+
+ # Bypass RX buffer
+ self.comb += [
+ self.rxphdlyreset.eq(0),
+ self.rxdlyen.eq(0),
+ self.rxphalign.eq(0),
+ self.rxphalignen.eq(0),
+ ]
+
# Instance
gtxe2_channel_parameters = {
# Simulation-Only Attributes