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 K7SATAPHYRXAlign
from lib.sata.k7sataphy.datapath import K7SATAPHYRXConvert, K7SATAPHYTXConvert
class K7SATAPHY(Module):
# CRG / CTRL
crg = K7SATAPHYCRG(pads, gtx, clk_freq, default_speed)
if host:
- ctrl = K7SATAPHYHostCtrl(gtx, clk_freq)
+ ctrl = K7SATAPHYHostCtrl(gtx, crg, clk_freq)
else:
- ctrl = K7SATAPHYDeviceCtrl(gtx, clk_freq)
+ ctrl = K7SATAPHYDeviceCtrl(gtx, crg, clk_freq)
self.submodules += crg, ctrl
- self.comb += ctrl.start.eq(crg.ready)
# DATAPATH
- rxalign = K7SATAPHYRXAlign()
rxconvert = K7SATAPHYRXConvert()
txconvert = K7SATAPHYTXConvert()
- self.submodules += rxalign, rxconvert, txconvert
+ self.submodules += rxconvert, txconvert
self.comb += [
- rxalign.rxdata_i.eq(gtx.rxdata),
- rxalign.rxcharisk_i.eq(gtx.rxcharisk),
- rxconvert.rxdata.eq(rxalign.rxdata_o),
- rxconvert.rxcharisk.eq(rxalign.rxcharisk_o),
+ rxconvert.rxdata.eq(gtx.rxdata),
+ rxconvert.rxcharisk.eq(gtx.rxcharisk),
gtx.txdata.eq(txconvert.txdata),
gtx.txcharisk.eq(txconvert.txcharisk)
txconvert.sink.charisk.eq(ctrl.txcharisk)
),
self.source.stb.eq(rxconvert.source.stb),
- self.source.payload.eq(rxconvert.source.payload),
- rxconvert.source.ack.eq(self.source.ack),
+ self.source.payload.eq(rxconvert.source.data),
+ rxconvert.source.ack.eq(1),
ctrl.rxdata.eq(rxconvert.source.data)
]
return ceil(t/clk_period_us)
class K7SATAPHYHostCtrl(Module):
- def __init__(self, gtx, clk_freq):
- self.start = Signal()
+ def __init__(self, gtx, crg, clk_freq):
self.ready = Signal()
self.txdata = Signal(32)
fsm.act("RESET",
gtx.txelecidle.eq(1),
- If(self.start,
+ If(crg.ready,
NextState("COMINIT")
)
)
)
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")
).Elif(~align_detect & align_timeout,
self.sync += \
If(fsm.ongoing("SEND_ALIGN"),
- If(self.rxdata[0:8] == K28_5,
+ If(self.rxdata[0:8] == 0xBC,
non_align_cnt.eq(non_align_cnt + 1)
).Else(
non_align_cnt.eq(0)
)
class K7SATAPHYDeviceCtrl(Module):
- def __init__(self, gtx, clk_freq):
- self.start = Signal()
+ def __init__(self, gtx, crg, clk_freq):
self.ready = Signal()
self.txdata = Signal(32)
fsm.act("RESET",
gtx.txelecidle.eq(1),
- If(self.start,
+ If(crg.ready,
NextState("AWAIT_COMINIT")
)
)
)
fsm.act("SEND_ALIGN",
gtx.txelecidle.eq(0),
+ gtx.rxalign.eq(1),
self.txdata.eq(ALIGN_VAL),
self.txcharisk.eq(0b0001),
If(align_detect,
from lib.sata.k7sataphy.std import *
-class K7SATAPHYRXAlign(Module):
+class K7SATAPHYRXConvert(Module):
def __init__(self, dw=16):
- self.rxdata_i = Signal(dw)
- self.rxcharisk_i = Signal(dw//8)
+ self.rxdata = Signal(dw)
+ self.rxcharisk = Signal(dw//8)
- self.rxdata_o = Signal(dw)
- self.rxcharisk_o = Signal(dw//8)
+ self.source = Source([("data", 32), ("charisk", 4)])
###
- rxdata_r = Signal(dw)
- rxcharisk_r = Signal(dw//8)
+ # byte alignment
+ rxdata_r = Signal(2*dw)
+ rxcharisk_r = Signal((2*dw)//8)
+ rxalignment = Signal(dw//8)
+ rxvalid = Signal()
self.sync.sata_rx += [
- rxdata_r.eq(self.rxdata_i),
- rxcharisk_r.eq(self.rxcharisk_i)
+ 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)
+ ).Else(
+ rxvalid.eq(~rxvalid)
+ )
]
+
+ rxdata = Signal(2*dw)
+ rxcharisk = Signal((2*dw)//8)
cases = {}
cases[1<<0] = [
- self.rxdata_o.eq(rxdata_r[0:dw]),
- self.rxcharisk_o.eq(rxcharisk_r[0:dw//8])
+ rxdata.eq(rxdata_r[0:]),
+ rxcharisk.eq(rxcharisk_r[0:])
]
for i in range(1, dw//8):
cases[1<<i] = [
- self.rxdata_o.eq(Cat(self.rxdata_i[8*i:dw], rxdata_r[0:8*i])),
- self.rxcharisk_o.eq(Cat(self.rxcharisk_i[i:dw//8], rxcharisk_r[0: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(rxcharisk_r, cases)
-
-class K7SATAPHYRXConvert(Module):
- def __init__(self):
- self.rxdata = Signal(16)
- self.rxcharisk = Signal(2)
-
- self.source = Source([("data", 32), ("charisk", 4)])
- ###
-
- # convert data widths
- rx_converter = RenameClockDomains(Converter([("raw", 16+2)], [("raw", 32+4)]), "sata_rx")
- self.submodules += rx_converter
- self.comb += [
- rx_converter.sink.stb.eq(1),
- rx_converter.sink.raw.eq(Cat(self.rxdata , self.rxcharisk)),
- rx_converter.source.ack.eq(1)
- ]
-
+ self.comb += Case(rxalignment, cases)
# clock domain crossing
- # SATA device is supposed to lock its tx frequency to its received rx frequency, so this
- # ensure that sata_rx and sata_tx clock have the same frequency with only not the same
- # phase and thus ensute the rx_fifo will never be full.
- rx_fifo = AsyncFIFO([("raw", 36)], 16)
+ rx_fifo = AsyncFIFO([("data", 32), ("charisk", 4)], 16)
self.submodules.rx_fifo = RenameClockDomains(rx_fifo, {"write": "sata_rx", "read": "sys"})
self.comb += [
- rx_converter.source.connect(self.rx_fifo.sink),
- self.rx_fifo.source.ack.eq(1),
+ rx_fifo.sink.stb.eq(rxvalid),
+ rx_fifo.sink.data.eq(rxdata),
+ rx_fifo.sink.charisk.eq(rxcharisk),
]
- # rearrange data
+ # connect source
self.comb += [
- self.source.stb.eq(self.rx_fifo.source.stb),
- self.source.payload.data.eq(Cat(rx_fifo.source.raw[0:16], rx_fifo.source.raw[18:18+16])),
- self.source.payload.charisk.eq(Cat(rx_fifo.source.raw[16:18], rx_fifo.source.raw[18+16:18+18])),
- self.rx_fifo.source.ack.eq(self.source.ack),
+ Record.connect(rx_fifo.source, self.source)
]
class K7SATAPHYTXConvert(Module):
# Receive Ports
self.rxuserrdy = Signal()
+ self.rxalign = Signal()
# Receive Ports - 8b10b Decoder
self.rxcharisk = Signal(2)
# Transmit Ports - TX Data Path interface
self.gttxreset = Signal()
- self.txdata = Signal()
+ self.txdata = Signal(16)
self.txoutclk = Signal()
self.txusrclk = Signal()
self.txusrclk2 = Signal()
rxphalignen = Signal()
rxphdlyreset = Signal()
rxrate = Signal(3)
+ rxalign = Signal()
self.specials += [
MultiReg(self.rxuserrdy, rxuserrdy, "sata_rx"),
MultiReg(self.rxphalign, rxphalign, "sata_rx"),
MultiReg(self.rxphalignen, rxphalignen, "sata_rx"),
MultiReg(self.rxphdlyreset, rxphdlyreset, "sata_rx"),
- MultiReg(self.rxrate, rxrate, "sata_rx")
+ MultiReg(self.rxrate, rxrate, "sata_rx"),
+ MultiReg(self.rxalign, rxalign, "sata_rx"),
]
_PulseSynchronizer(rxcomwakedet, "sata_rx", self.rxcomwakedet, "sys"),
]
+
+ self.rxbyteisaligned = Signal()
+ self.rxbyterealign = Signal()
+ self.rxcommadet = Signal()
+
# Instance
gtxe2_channel_parameters = {
# Simulation-Only Attributes
"p_ALIGN_COMMA_ENABLE":ones(10),
"p_ALIGN_COMMA_WORD":2,
"p_ALIGN_MCOMMA_DET":"TRUE",
- "p_ALIGN_MCOMMA_VALUE":K28_5,
+ "p_ALIGN_MCOMMA_VALUE":0b1010000011,
"p_ALIGN_PCOMMA_DET":"TRUE",
- "p_ALIGN_PCOMMA_VALUE":~K28_5,
+ "p_ALIGN_PCOMMA_VALUE":0b0101111100,
"p_SHOW_REALIGN_COMMA":"FALSE",
"p_RXSLIDE_AUTO_WAIT":7,
"p_RXSLIDE_MODE":"OFF",
#o_RXSTATUS=,
# Receive Ports - RX Byte and Word Alignment Ports
- #o_RXBYTEISALIGNED=,
- #o_RXBYTEREALIGN=,
- #o_RXCOMMADET=,
+ o_RXBYTEISALIGNED=self.rxbyteisaligned,
+ o_RXBYTEREALIGN=self.rxbyterealign,
+ o_RXCOMMADET=self.rxcommadet,
i_RXCOMMADETEN=1,
- i_RXMCOMMAALIGNEN=0,
- i_RXPCOMMAALIGNEN=0,
+ i_RXMCOMMAALIGNEN=rxalign,
+ i_RXPCOMMAALIGNEN=rxalign,
# Receive Ports - RX Channel Bonding Ports
#o_RXCHANBONDSEQ=,
from migen.fhdl.std import *
from migen.genlib.record import *
-K28_5 = 0b1010000011
-
ALIGN_VAL = 0x7B4A4ABC
-CONT_VAL = 0x9999AA7C
-DMAT_VAL = 0x3636B57C
-EOF_VAL = 0xD5D5B57C
-HOLD_VAL = 0xD5D5AA7C
-HOLDA_VAL = 0x9595AA7C
-PMACK_VAL = 0x9595957C
-PMNAK_VAL = 0xF5F5957C
-PMREQ_P_VAL = 0x1717B57C
-PMREQ_S_VAL = 0x7575957C
-R_ERR_VAL = 0x5656B57C
-R_IP_VAL = 0x5555B57C
-R_OK_VAL = 0x3535B57C
-R_RDY_VAL = 0x4A4A957C
-SOF_VAL = 0x3737B57C
SYNC_VAL = 0xB5B5957C
-WTRM_VAL = 0x5858B57C
-X_RDY_VAL = 0x5757B57C
def ones(width):
return 2**width-1