mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
litesata: use (some) settings from vivado 2015.1, try to follow all ug476 recommendations to initialize GTX (...), remove automatic reset on top.
Works fine @ 3Gbps, still not working @6.0Gbps
This commit is contained in:
parent
5d5d5edfe2
commit
7bdcbc94cd
7 changed files with 268 additions and 205 deletions
|
@ -19,7 +19,6 @@ from misoclib.mem.litesata import LiteSATA
|
|||
class _CRG(Module):
|
||||
def __init__(self, platform):
|
||||
self.clock_domains.cd_sys = ClockDomain()
|
||||
self.reset = Signal()
|
||||
|
||||
clk200 = platform.request("clk200")
|
||||
clk200_se = Signal()
|
||||
|
@ -49,7 +48,7 @@ class _CRG(Module):
|
|||
p_CLKOUT4_DIVIDE=2, p_CLKOUT4_PHASE=0.0, #o_CLKOUT4=
|
||||
),
|
||||
Instance("BUFG", i_I=pll_sys, o_O=self.cd_sys.clk),
|
||||
AsyncResetSynchronizer(self.cd_sys, ~pll_locked | platform.request("cpu_reset") | self.reset),
|
||||
AsyncResetSynchronizer(self.cd_sys, ~pll_locked | platform.request("cpu_reset")),
|
||||
]
|
||||
|
||||
|
||||
|
@ -106,7 +105,6 @@ class BISTSoC(SoC, AutoCSR):
|
|||
|
||||
# SATA PHY/Core/Frontend
|
||||
self.submodules.sata_phy = LiteSATAPHY(platform.device, platform.request("sata"), "sata_gen2", clk_freq)
|
||||
self.comb += self.crg.reset.eq(self.sata_phy.ctrl.need_reset) # XXX FIXME
|
||||
self.submodules.sata = LiteSATA(self.sata_phy, with_bist=True, with_bist_csr=True)
|
||||
|
||||
# Status Leds
|
||||
|
|
|
@ -191,7 +191,7 @@ if __name__ == "__main__":
|
|||
|
||||
print("sector={:d}({:d}MB) wr_speed={:4.2f}MB/s rd_speed={:4.2f}MB/s errors={:d} retry={:d}".format(
|
||||
sector,
|
||||
run_sectors*logical_sector_size/MB,
|
||||
int(run_sectors*logical_sector_size/MB),
|
||||
write_speed/MB,
|
||||
read_speed/MB,
|
||||
write_errors + read_errors,
|
||||
|
|
|
@ -7,6 +7,7 @@ class LiteSATAPHY(Module):
|
|||
def __init__(self, device, pads, revision, clk_freq):
|
||||
self.pads = pads
|
||||
self.revision = revision
|
||||
|
||||
# Transceiver / Clocks
|
||||
if device[:3] == "xc7": # Kintex 7
|
||||
from misoclib.mem.litesata.phy.k7.trx import K7LiteSATAPHYTRX
|
||||
|
@ -14,8 +15,7 @@ class LiteSATAPHY(Module):
|
|||
self.submodules.trx = K7LiteSATAPHYTRX(pads, revision)
|
||||
self.submodules.crg = K7LiteSATAPHYCRG(pads, self.trx, revision, clk_freq)
|
||||
else:
|
||||
msg = "Device" + device + "not (yet) supported."
|
||||
raise NotImplementedError(msg)
|
||||
raise NotImplementedError
|
||||
|
||||
# Control
|
||||
self.submodules.ctrl = LiteSATAPHYCtrl(self.trx, self.crg, clk_freq)
|
||||
|
|
|
@ -1,15 +1,10 @@
|
|||
from misoclib.mem.litesata.common import *
|
||||
|
||||
|
||||
def us(t, clk_freq):
|
||||
clk_period_us = 1000000/clk_freq
|
||||
return math.ceil(t/clk_period_us)
|
||||
|
||||
|
||||
class LiteSATAPHYCtrl(Module):
|
||||
def __init__(self, trx, crg, clk_freq):
|
||||
self.clk_freq = clk_freq
|
||||
self.ready = Signal()
|
||||
self.need_reset = Signal()
|
||||
self.sink = sink = Sink(phy_description(32))
|
||||
self.source = source = Source(phy_description(32))
|
||||
|
||||
|
@ -20,47 +15,47 @@ class LiteSATAPHYCtrl(Module):
|
|||
sink.ack.eq(1)
|
||||
]
|
||||
|
||||
retry_timeout = Timeout(us(10000, clk_freq))
|
||||
align_timeout = Timeout(us(873, clk_freq))
|
||||
retry_timeout = Timeout(self.us(10000))
|
||||
align_timeout = Timeout(self.us(873))
|
||||
self.submodules += align_timeout, retry_timeout
|
||||
|
||||
align_detect = Signal()
|
||||
non_align_cnt = Signal(4)
|
||||
non_align_counter = Counter(4)
|
||||
self.submodules += non_align_counter
|
||||
|
||||
self.fsm = fsm = FSM(reset_state="RESET")
|
||||
self.fsm = fsm = InsertReset(FSM(reset_state="RESET"))
|
||||
self.submodules += fsm
|
||||
self.comb += fsm.reset.eq(retry_timeout.reached | align_timeout.reached)
|
||||
fsm.act("RESET",
|
||||
trx.tx_idle.eq(1),
|
||||
retry_timeout.reset.eq(1),
|
||||
align_timeout.reset.eq(1),
|
||||
non_align_counter.reset.eq(1),
|
||||
If(crg.ready,
|
||||
NextState("COMINIT")
|
||||
),
|
||||
)
|
||||
)
|
||||
fsm.act("COMINIT",
|
||||
trx.tx_idle.eq(1),
|
||||
trx.tx_cominit_stb.eq(1),
|
||||
If(trx.tx_cominit_ack & ~trx.rx_cominit_stb,
|
||||
NextState("AWAIT_COMINIT")
|
||||
),
|
||||
)
|
||||
)
|
||||
fsm.act("AWAIT_COMINIT",
|
||||
trx.tx_idle.eq(1),
|
||||
retry_timeout.ce.eq(1),
|
||||
If(trx.rx_cominit_stb,
|
||||
NextState("AWAIT_NO_COMINIT")
|
||||
).Else(
|
||||
If(retry_timeout.reached,
|
||||
NextState("RESET")
|
||||
)
|
||||
),
|
||||
)
|
||||
)
|
||||
fsm.act("AWAIT_NO_COMINIT",
|
||||
trx.tx_idle.eq(1),
|
||||
retry_timeout.reset.eq(1),
|
||||
If(~trx.rx_cominit_stb,
|
||||
NextState("CALIBRATE")
|
||||
),
|
||||
)
|
||||
)
|
||||
fsm.act("CALIBRATE",
|
||||
trx.tx_idle.eq(1),
|
||||
|
@ -71,34 +66,31 @@ class LiteSATAPHYCtrl(Module):
|
|||
trx.tx_comwake_stb.eq(1),
|
||||
If(trx.tx_comwake_ack,
|
||||
NextState("AWAIT_COMWAKE")
|
||||
),
|
||||
)
|
||||
)
|
||||
fsm.act("AWAIT_COMWAKE",
|
||||
trx.tx_idle.eq(1),
|
||||
retry_timeout.ce.eq(1),
|
||||
If(trx.rx_comwake_stb,
|
||||
NextState("AWAIT_NO_COMWAKE")
|
||||
).Else(
|
||||
If(retry_timeout.reached,
|
||||
NextState("RESET")
|
||||
)
|
||||
),
|
||||
)
|
||||
)
|
||||
fsm.act("AWAIT_NO_COMWAKE",
|
||||
trx.tx_idle.eq(1),
|
||||
If(~trx.rx_comwake_stb,
|
||||
NextState("AWAIT_NO_RX_IDLE")
|
||||
),
|
||||
)
|
||||
)
|
||||
fsm.act("AWAIT_NO_RX_IDLE",
|
||||
trx.tx_idle.eq(0),
|
||||
source.data.eq(0x4A4A4A4A), # D10.2
|
||||
source.charisk.eq(0b0000),
|
||||
align_timeout.ce.eq(1),
|
||||
If(~trx.rx_idle,
|
||||
NextState("AWAIT_ALIGN"),
|
||||
crg.reset.eq(1),
|
||||
trx.pmarxreset.eq(1)
|
||||
),
|
||||
crg.tx_reset.eq(1),
|
||||
crg.rx_reset.eq(1)
|
||||
)
|
||||
)
|
||||
fsm.act("AWAIT_ALIGN",
|
||||
trx.tx_idle.eq(0),
|
||||
|
@ -108,47 +100,39 @@ class LiteSATAPHYCtrl(Module):
|
|||
align_timeout.ce.eq(1),
|
||||
If(align_detect & ~trx.rx_idle,
|
||||
NextState("SEND_ALIGN")
|
||||
).Elif(align_timeout.reached,
|
||||
NextState("RESET")
|
||||
),
|
||||
)
|
||||
)
|
||||
fsm.act("SEND_ALIGN",
|
||||
trx.tx_idle.eq(0),
|
||||
trx.rx_align.eq(1),
|
||||
align_timeout.ce.eq(1),
|
||||
source.data.eq(primitives["ALIGN"]),
|
||||
source.charisk.eq(0b0001),
|
||||
If(non_align_cnt == 3,
|
||||
NextState("READY")
|
||||
If(sink.stb,
|
||||
If(sink.data[0:8] == 0x7C,
|
||||
non_align_counter.ce.eq(1)
|
||||
).Else(
|
||||
non_align_counter.reset.eq(1)
|
||||
)
|
||||
),
|
||||
If(non_align_counter.value == 3,
|
||||
NextState("READY")
|
||||
)
|
||||
)
|
||||
fsm.act("READY",
|
||||
trx.tx_idle.eq(0),
|
||||
trx.rx_align.eq(1),
|
||||
source.data.eq(primitives["SYNC"]),
|
||||
source.charisk.eq(0b0001),
|
||||
If(trx.rx_idle,
|
||||
NextState("RESET")
|
||||
),
|
||||
self.ready.eq(1),
|
||||
If(trx.rx_idle,
|
||||
NextState("RESET"),
|
||||
)
|
||||
)
|
||||
|
||||
reset_timeout = Timeout(clk_freq//16)
|
||||
self.submodules += reset_timeout
|
||||
self.comb += [
|
||||
reset_timeout.ce.eq(~self.ready),
|
||||
self.need_reset.eq(reset_timeout.reached)
|
||||
]
|
||||
self.comb += align_detect.eq(self.sink.stb &
|
||||
(self.sink.data == primitives["ALIGN"]))
|
||||
|
||||
self.comb += \
|
||||
align_detect.eq(self.sink.stb &
|
||||
(self.sink.data == primitives["ALIGN"]))
|
||||
self.sync += \
|
||||
If(fsm.ongoing("SEND_ALIGN"),
|
||||
If(sink.stb,
|
||||
If(sink.data[0:8] == 0x7C,
|
||||
non_align_cnt.eq(non_align_cnt + 1)
|
||||
).Else(
|
||||
non_align_cnt.eq(0)
|
||||
)
|
||||
)
|
||||
)
|
||||
def us(self, t):
|
||||
clk_period_us = 1000000/self.clk_freq
|
||||
return math.ceil(t/clk_period_us)
|
||||
|
|
|
@ -8,7 +8,7 @@ class LiteSATAPHYDatapathRX(Module):
|
|||
|
||||
# # #
|
||||
|
||||
# width convertion (16 to 32) and byte alignment
|
||||
# width convertion (16 to 32) and byte alignment
|
||||
byte_alignment = Signal()
|
||||
last_charisk = Signal(2)
|
||||
last_data = Signal(16)
|
||||
|
@ -38,13 +38,13 @@ class LiteSATAPHYDatapathRX(Module):
|
|||
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)
|
||||
# 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
|
||||
|
@ -61,18 +61,18 @@ class LiteSATAPHYDatapathTX(Module):
|
|||
|
||||
# # #
|
||||
|
||||
# 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)
|
||||
# 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)
|
||||
# width convertion (32 to 16)
|
||||
converter = Converter(phy_description(32),
|
||||
phy_description(16),
|
||||
reverse=False)
|
||||
|
@ -143,7 +143,7 @@ class LiteSATAPHYDatapath(Module):
|
|||
|
||||
# # #
|
||||
|
||||
# TX path
|
||||
# TX path
|
||||
align_inserter = LiteSATAPHYAlignInserter(ctrl)
|
||||
mux = Multiplexer(phy_description(32), 2)
|
||||
tx = LiteSATAPHYDatapathTX()
|
||||
|
@ -157,7 +157,7 @@ class LiteSATAPHYDatapath(Module):
|
|||
Record.connect(tx.source, trx.sink)
|
||||
]
|
||||
|
||||
# RX path
|
||||
# RX path
|
||||
rx = LiteSATAPHYDatapathRX()
|
||||
demux = Demultiplexer(phy_description(32), 2)
|
||||
align_remover = LiteSATAPHYAlignRemover()
|
||||
|
|
|
@ -3,15 +3,17 @@ from misoclib.mem.litesata.common import *
|
|||
|
||||
class K7LiteSATAPHYCRG(Module):
|
||||
def __init__(self, pads, gtx, revision, clk_freq):
|
||||
self.reset = Signal()
|
||||
self.tx_reset = Signal()
|
||||
self.rx_reset = Signal()
|
||||
self.ready = Signal()
|
||||
|
||||
self.clock_domains.cd_sata_tx = ClockDomain()
|
||||
self.clock_domains.cd_sata_rx = ClockDomain()
|
||||
|
||||
# CPLL
|
||||
# (sata_gen3) 150MHz / VCO @ 3GHz / Line rate @ 6Gbps
|
||||
# (sata_gen2 & sata_gen1) VCO still @ 3 GHz, Line rate is decreased with output dividers.
|
||||
# CPLL
|
||||
# (sata_gen3) 150MHz / VCO @ 3GHz / Line rate @ 6Gbps
|
||||
# (sata_gen2 & sata_gen1) VCO still @ 3 GHz, Line rate is
|
||||
# decreased with output dividers.
|
||||
refclk = Signal()
|
||||
self.specials += Instance("IBUFDS_GTE2",
|
||||
i_CEB=0,
|
||||
|
@ -21,19 +23,19 @@ class K7LiteSATAPHYCRG(Module):
|
|||
)
|
||||
self.comb += gtx.gtrefclk0.eq(refclk)
|
||||
|
||||
# TX clocking
|
||||
# (sata_gen3) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 300MHz (16-bits)
|
||||
# (sata_gen2) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 150MHz (16-bits)
|
||||
# (sata_gen1) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 75MHz (16-bits)
|
||||
# TX clocking
|
||||
# (sata_gen3) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 300MHz (16-bits)
|
||||
# (sata_gen2) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 150MHz (16-bits)
|
||||
# (sata_gen1) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 75MHz (16-bits)
|
||||
mmcm_reset = Signal()
|
||||
mmcm_locked = Signal()
|
||||
mmcm_fb = Signal()
|
||||
mmcm_clk_i = Signal()
|
||||
mmcm_clk0_o = Signal()
|
||||
mmcm_div_config = {
|
||||
"sata_gen1": 16.0,
|
||||
"sata_gen1": 16.0,
|
||||
"sata_gen2": 8.0,
|
||||
"sata_gen3": 4.0
|
||||
"sata_gen3": 4.0
|
||||
}
|
||||
mmcm_div = mmcm_div_config[revision]
|
||||
self.specials += [
|
||||
|
@ -60,10 +62,10 @@ class K7LiteSATAPHYCRG(Module):
|
|||
gtx.txusrclk2.eq(self.cd_sata_tx.clk)
|
||||
]
|
||||
|
||||
# RX clocking
|
||||
# (sata_gen3) sata_rx recovered clk @ 300MHz from GTX RXOUTCLK
|
||||
# (sata_gen2) sata_rx recovered clk @ 150MHz from GTX RXOUTCLK
|
||||
# (sata_gen1) sata_rx recovered clk @ 150MHz from GTX RXOUTCLK
|
||||
# RX clocking
|
||||
# (sata_gen3) sata_rx recovered clk @ 300MHz from GTX RXOUTCLK
|
||||
# (sata_gen2) sata_rx recovered clk @ 150MHz from GTX RXOUTCLK
|
||||
# (sata_gen1) sata_rx recovered clk @ 150MHz from GTX RXOUTCLK
|
||||
self.specials += [
|
||||
Instance("BUFG", i_I=gtx.rxoutclk, o_O=self.cd_sata_rx.clk),
|
||||
]
|
||||
|
@ -72,85 +74,154 @@ class K7LiteSATAPHYCRG(Module):
|
|||
gtx.rxusrclk2.eq(self.cd_sata_rx.clk)
|
||||
]
|
||||
|
||||
# Configuration Reset
|
||||
# After configuration, GTX's resets have to stay low for at least 500ns
|
||||
# See AR43482
|
||||
reset_en = Signal()
|
||||
clk_period_ns = 1000000000/clk_freq
|
||||
reset_en_cnt_max = math.ceil(500/clk_period_ns)
|
||||
reset_en_cnt = Signal(max=reset_en_cnt_max, reset=reset_en_cnt_max-1)
|
||||
self.sync += \
|
||||
If(self.reset,
|
||||
reset_en_cnt.eq(reset_en_cnt.reset)
|
||||
).Elif(~reset_en,
|
||||
reset_en_cnt.eq(reset_en_cnt-1)
|
||||
)
|
||||
self.comb += reset_en.eq(reset_en_cnt == 0)
|
||||
# Configuration Reset
|
||||
# After configuration, GTX's resets have to stay low for at least 500ns
|
||||
# See AR43482
|
||||
startup_cycles = math.ceil(500*clk_freq/1000000000)
|
||||
startup_wait = Timeout(startup_cycles)
|
||||
self.submodules += startup_wait
|
||||
self.comb += [
|
||||
startup_wait.reset.eq(self.tx_reset | self.rx_reset),
|
||||
startup_wait.ce.eq(1)
|
||||
]
|
||||
|
||||
# TX Reset FSM
|
||||
tx_reset_fsm = InsertReset(FSM(reset_state="IDLE"))
|
||||
self.submodules += tx_reset_fsm
|
||||
self.comb += tx_reset_fsm.reset.eq(self.reset)
|
||||
tx_reset_fsm.act("IDLE",
|
||||
If(reset_en,
|
||||
NextState("RESET_GTX"),
|
||||
# TX Startup FSM
|
||||
self.tx_ready = Signal()
|
||||
tx_startup_fsm = InsertReset(FSM(reset_state="IDLE"))
|
||||
self.submodules += tx_startup_fsm
|
||||
# Wait 500ns of AR43482
|
||||
tx_startup_fsm.act("IDLE",
|
||||
If(startup_wait.reached,
|
||||
NextState("RESET_ALL"),
|
||||
)
|
||||
)
|
||||
tx_reset_fsm.act("RESET_GTX",
|
||||
# Reset CPLL, MMCM, GTX
|
||||
tx_startup_fsm.act("RESET_ALL",
|
||||
gtx.cpllreset.eq(1),
|
||||
mmcm_reset.eq(1),
|
||||
gtx.gttxreset.eq(1),
|
||||
If(gtx.cplllock & mmcm_locked,
|
||||
NextState("RELEASE_CPLL"),
|
||||
)
|
||||
# Release CPLL reset and wait for lock
|
||||
tx_startup_fsm.act("RELEASE_CPLL",
|
||||
mmcm_reset.eq(1),
|
||||
gtx.gttxreset.eq(1),
|
||||
If(gtx.cplllock,
|
||||
NextState("RELEASE_MMCM"),
|
||||
)
|
||||
)
|
||||
# Release MMCM reset and wait for lock
|
||||
tx_startup_fsm.act("RELEASE_MMCM",
|
||||
gtx.gttxreset.eq(1),
|
||||
If(mmcm_locked,
|
||||
NextState("RELEASE_GTX")
|
||||
)
|
||||
)
|
||||
tx_reset_fsm.act("RELEASE_GTX",
|
||||
# Release GTX reset and wait for GTX resetdone
|
||||
# (from UG476, GTX is reseted on falling edge
|
||||
# of gttxreset)
|
||||
tx_startup_fsm.act("RELEASE_GTX",
|
||||
gtx.txuserrdy.eq(1),
|
||||
If(gtx.txresetdone,
|
||||
NextState("READY")
|
||||
)
|
||||
)
|
||||
tx_reset_fsm.act("READY",
|
||||
gtx.txuserrdy.eq(1)
|
||||
# Start Delay alignment (Pulse)
|
||||
tx_startup_fsm.act("ALIGN",
|
||||
gtx.txuserrdy.eq(1),
|
||||
gtx.txdlyreset.eq(1),
|
||||
NextState("WAIT_ALIGN")
|
||||
)
|
||||
|
||||
# RX Reset FSM
|
||||
rx_reset_fsm = InsertReset(FSM(reset_state="IDLE"))
|
||||
self.submodules += rx_reset_fsm
|
||||
self.comb += rx_reset_fsm.reset.eq(self.reset)
|
||||
|
||||
rx_reset_fsm.act("IDLE",
|
||||
If(reset_en,
|
||||
NextState("RESET_GTX"),
|
||||
)
|
||||
)
|
||||
rx_reset_fsm.act("RESET_GTX",
|
||||
gtx.gtrxreset.eq(1),
|
||||
If(gtx.cplllock & mmcm_locked,
|
||||
NextState("RELEASE_GTX")
|
||||
)
|
||||
)
|
||||
rx_reset_fsm.act("RELEASE_GTX",
|
||||
gtx.rxuserrdy.eq(1),
|
||||
If(gtx.rxresetdone,
|
||||
# Wait Delay alignment
|
||||
tx_startup_fsm.act("WAIT_ALIGN",
|
||||
gtx.txuserrdy.eq(1),
|
||||
If(gtx.txdlyresetdone,
|
||||
NextState("READY")
|
||||
)
|
||||
)
|
||||
rx_reset_fsm.act("READY",
|
||||
gtx.rxuserrdy.eq(1)
|
||||
tx_startup_fsm.act("READY",
|
||||
gtx.txuserrdy.eq(1),
|
||||
self.tx_ready.eq(1)
|
||||
)
|
||||
|
||||
# Ready
|
||||
self.tx_ready = tx_reset_fsm.ongoing("READY")
|
||||
self.rx_ready = rx_reset_fsm.ongoing("READY")
|
||||
tx_ready_timeout = Timeout(1*clk_freq//1000)
|
||||
self.submodules += tx_ready_timeout
|
||||
self.comb += [
|
||||
tx_ready_timeout.reset.eq(self.tx_reset | self.tx_ready),
|
||||
tx_ready_timeout.ce.eq(~self.tx_ready),
|
||||
tx_startup_fsm.reset.eq(self.tx_reset | tx_ready_timeout.reached),
|
||||
]
|
||||
|
||||
|
||||
# RX Startup FSM
|
||||
self.rx_ready = Signal()
|
||||
rx_startup_fsm = InsertReset(FSM(reset_state="IDLE"))
|
||||
self.submodules += rx_startup_fsm
|
||||
|
||||
cdr_stable = Timeout(2048)
|
||||
self.submodules += cdr_stable
|
||||
self.comb += cdr_stable.ce.eq(1),
|
||||
|
||||
# Wait 500ns of AR43482
|
||||
rx_startup_fsm.act("IDLE",
|
||||
cdr_stable.reset.eq(1),
|
||||
If(startup_wait.reached,
|
||||
NextState("RESET_GTX"),
|
||||
)
|
||||
)
|
||||
# Reset GTX
|
||||
rx_startup_fsm.act("RESET_GTX",
|
||||
gtx.gtrxreset.eq(1),
|
||||
NextState("WAIT_CPLL")
|
||||
)
|
||||
# Wait for CPLL lock
|
||||
rx_startup_fsm.act("WAIT_CPLL",
|
||||
gtx.gtrxreset.eq(1),
|
||||
If(gtx.cplllock,
|
||||
NextState("RELEASE_GTX"),
|
||||
cdr_stable.reset.eq(1)
|
||||
)
|
||||
)
|
||||
# Release GTX reset and wait for GTX resetdone
|
||||
# (from UG476, GTX is reseted on falling edge
|
||||
# of gttxreset)
|
||||
rx_startup_fsm.act("RELEASE_GTX",
|
||||
gtx.rxuserrdy.eq(1),
|
||||
If(gtx.rxresetdone & cdr_stable.reached,
|
||||
NextState("ALIGN")
|
||||
)
|
||||
)
|
||||
# Start Delay alignment (Pulse)
|
||||
rx_startup_fsm.act("ALIGN",
|
||||
gtx.rxuserrdy.eq(1),
|
||||
gtx.rxdlyreset.eq(1),
|
||||
NextState("WAIT_ALIGN")
|
||||
)
|
||||
# Wait Delay alignment
|
||||
rx_startup_fsm.act("WAIT_ALIGN",
|
||||
gtx.rxuserrdy.eq(1),
|
||||
If(gtx.rxdlyresetdone,
|
||||
NextState("READY")
|
||||
)
|
||||
)
|
||||
rx_startup_fsm.act("READY",
|
||||
gtx.rxuserrdy.eq(1),
|
||||
self.rx_ready.eq(1)
|
||||
)
|
||||
|
||||
rx_ready_timeout = Timeout(1*clk_freq//1000)
|
||||
self.submodules += rx_ready_timeout
|
||||
self.comb += [
|
||||
rx_ready_timeout.reset.eq(self.rx_reset | self.rx_ready),
|
||||
rx_ready_timeout.ce.eq(~self.rx_ready),
|
||||
rx_startup_fsm.reset.eq(self.rx_reset | rx_ready_timeout.reached),
|
||||
]
|
||||
|
||||
# Ready
|
||||
self.comb += self.ready.eq(self.tx_ready & self.rx_ready)
|
||||
|
||||
# Reset PLL
|
||||
self.comb += gtx.cpllreset.eq(ResetSignal() | self.reset | ~reset_en)
|
||||
|
||||
# Reset MMCM
|
||||
self.comb += mmcm_reset.eq(ResetSignal() | self.reset | ~gtx.cplllock)
|
||||
|
||||
# Reset for SATA TX/RX clock domains
|
||||
# Reset for SATA TX/RX clock domains
|
||||
self.specials += [
|
||||
AsyncResetSynchronizer(self.cd_sata_tx, ~self.tx_ready),
|
||||
AsyncResetSynchronizer(self.cd_sata_rx, ~self.rx_ready),
|
||||
AsyncResetSynchronizer(self.cd_sata_tx, ~(gtx.cplllock & mmcm_locked) | self.tx_reset),
|
||||
AsyncResetSynchronizer(self.cd_sata_rx, ~gtx.cplllock | self.rx_reset),
|
||||
]
|
||||
|
|
|
@ -21,23 +21,39 @@ class _RisingEdge(Module):
|
|||
self.comb += o.eq(i & ~i_d)
|
||||
|
||||
|
||||
class _LowPassFilter(Module):
|
||||
def __init__(self, i, o, cycles):
|
||||
i_d = Signal()
|
||||
self.submodules.timeout = Timeout(cycles)
|
||||
self.sync += [
|
||||
i_d.eq(i),
|
||||
If(self.timeout.reached,
|
||||
o.eq(i_d)
|
||||
)
|
||||
]
|
||||
self.comb += [
|
||||
self.timeout.reset.eq(i != i_d),
|
||||
self.timeout.ce.eq(1)
|
||||
]
|
||||
|
||||
|
||||
class K7LiteSATAPHYTRX(Module):
|
||||
def __init__(self, pads, revision):
|
||||
# Common signals
|
||||
|
||||
# control
|
||||
self.tx_idle = Signal() #i
|
||||
self.tx_idle = Signal() #i
|
||||
|
||||
self.tx_cominit_stb = Signal() #i
|
||||
self.tx_cominit_ack = Signal() #o
|
||||
self.tx_comwake_stb = Signal() #i
|
||||
self.tx_comwake_ack = Signal() #o
|
||||
self.tx_comwake_ack = Signal() #o
|
||||
|
||||
self.rx_idle = Signal() #o
|
||||
self.rx_idle = Signal() #o
|
||||
self.rx_align = Signal() #i
|
||||
|
||||
self.rx_cominit_stb = Signal() #o
|
||||
self.rx_comwake_stb = Signal() #o
|
||||
self.rx_cominit_stb = Signal() #o
|
||||
self.rx_comwake_stb = Signal() #o
|
||||
|
||||
# datapath
|
||||
self.sink = Sink(phy_description(16))
|
||||
|
@ -53,15 +69,12 @@ class K7LiteSATAPHYTRX(Module):
|
|||
|
||||
# Receive Ports
|
||||
self.rxuserrdy = Signal()
|
||||
self.rxalign = Signal()
|
||||
|
||||
# Receive Ports - 8b10b Decoder
|
||||
self.rxcharisk = Signal(2)
|
||||
self.rxdisperr = Signal(2)
|
||||
|
||||
# Receive Ports - RX Data Path interface
|
||||
self.gtrxreset = Signal()
|
||||
self.pmarxreset = Signal()
|
||||
self.rxdata = Signal(16)
|
||||
self.rxoutclk = Signal()
|
||||
self.rxusrclk = Signal()
|
||||
|
@ -72,6 +85,8 @@ class K7LiteSATAPHYTRX(Module):
|
|||
|
||||
# Receive Ports - RX PLL Ports
|
||||
self.rxresetdone = Signal()
|
||||
self.rxdlyreset = Signal()
|
||||
self.rxdlyresetdone = Signal()
|
||||
|
||||
# Receive Ports - RX Ports for SATA
|
||||
self.rxcominitdet = Signal()
|
||||
|
@ -92,6 +107,8 @@ class K7LiteSATAPHYTRX(Module):
|
|||
|
||||
# Transmit Ports - TX PLL Ports
|
||||
self.txresetdone = Signal()
|
||||
self.txdlyreset = Signal()
|
||||
self.txdlyresetdone = Signal()
|
||||
|
||||
# Transmit Ports - TX Ports for PCI Express
|
||||
self.txelecidle = Signal(reset=1)
|
||||
|
@ -100,8 +117,6 @@ class K7LiteSATAPHYTRX(Module):
|
|||
self.txcomfinish = Signal()
|
||||
self.txcominit = Signal()
|
||||
self.txcomwake = Signal()
|
||||
self.txrate = Signal(3)
|
||||
self.rxcdrlock = Signal()
|
||||
|
||||
# Config at startup
|
||||
div_config = {
|
||||
|
@ -125,7 +140,6 @@ class K7LiteSATAPHYTRX(Module):
|
|||
self.tx_cominit_ack.eq(self.tx_cominit_stb & self.txcomfinish),
|
||||
self.tx_comwake_ack.eq(self.tx_comwake_stb & self.txcomfinish),
|
||||
self.rx_idle.eq(self.rxelecidle),
|
||||
self.rxalign.eq(self.rx_align),
|
||||
self.rx_cominit_stb.eq(self.rxcominitdet),
|
||||
self.rx_comwake_stb.eq(self.rxcomwakedet),
|
||||
]
|
||||
|
@ -150,16 +164,19 @@ class K7LiteSATAPHYTRX(Module):
|
|||
txelecidle = Signal(reset=1)
|
||||
txcominit = Signal()
|
||||
txcomwake = Signal()
|
||||
txrate = Signal(3)
|
||||
txdlyreset = Signal()
|
||||
txdlyresetdone = Signal()
|
||||
gttxreset = Signal()
|
||||
|
||||
self.specials += [
|
||||
MultiReg(self.txuserrdy, txuserrdy, "sata_tx"),
|
||||
MultiReg(self.txelecidle, txelecidle, "sata_tx"),
|
||||
MultiReg(self.txrate, txrate, "sata_tx")
|
||||
MultiReg(self.gttxreset, gttxreset, "sata_tx"),
|
||||
]
|
||||
self.submodules += [
|
||||
_PulseSynchronizer(self.txcominit, "sys", txcominit, "sata_tx"),
|
||||
_PulseSynchronizer(self.txcomwake, "sys", txcomwake, "sata_tx"),
|
||||
_PulseSynchronizer(self.txdlyreset, "sys", txdlyreset, "sata_tx"),
|
||||
]
|
||||
|
||||
# sata_tx clk --> sys clk
|
||||
|
@ -168,6 +185,7 @@ class K7LiteSATAPHYTRX(Module):
|
|||
|
||||
self.specials += [
|
||||
MultiReg(txresetdone, self.txresetdone, "sys"),
|
||||
MultiReg(txdlyresetdone, self.txdlyresetdone, "sys"),
|
||||
]
|
||||
|
||||
self.submodules += [
|
||||
|
@ -176,43 +194,35 @@ class K7LiteSATAPHYTRX(Module):
|
|||
|
||||
# sys clk --> sata_rx clk
|
||||
rxuserrdy = Signal()
|
||||
rxdlyreset = Signal()
|
||||
|
||||
self.specials += [
|
||||
MultiReg(self.rxuserrdy, rxuserrdy, "sata_rx"),
|
||||
]
|
||||
|
||||
self.submodules += [
|
||||
_PulseSynchronizer(self.rxdlyreset, "sys", rxdlyreset, "sata_rx"),
|
||||
]
|
||||
|
||||
# sata_rx clk --> sys clk
|
||||
rxelecidle = Signal()
|
||||
rxelecidle_i = Signal()
|
||||
rxelecidle_cnt_i = Signal(9)
|
||||
rxresetdone = Signal()
|
||||
rxcominitdet = Signal()
|
||||
rxcomwakedet = Signal()
|
||||
rxratedone = Signal()
|
||||
rxcdrlock = Signal()
|
||||
rxdlyresetdone = Signal()
|
||||
|
||||
self.specials += [
|
||||
MultiReg(rxelecidle, rxelecidle_i, "sys"),
|
||||
MultiReg(rxresetdone, self.rxresetdone, "sys"),
|
||||
MultiReg(rxcominitdet, self.rxcominitdet, "sys"),
|
||||
MultiReg(rxcomwakedet, self.rxcomwakedet, "sys"),
|
||||
MultiReg(rxcdrlock, self.rxcdrlock, "sys"),
|
||||
MultiReg(rxdlyresetdone, self.rxdlyresetdone, "sys"),
|
||||
]
|
||||
|
||||
self.sync += [
|
||||
If(rxelecidle_i != self.rxelecidle,
|
||||
If(rxelecidle_cnt_i == 0,
|
||||
self.rxelecidle.eq(rxelecidle_i),
|
||||
rxelecidle_cnt_i.eq(255)
|
||||
).Else(
|
||||
rxelecidle_cnt_i.eq(rxelecidle_cnt_i-1)
|
||||
)
|
||||
).Else(
|
||||
rxelecidle_cnt_i.eq(255)
|
||||
)
|
||||
]
|
||||
|
||||
self.rxbyteisaligned = Signal()
|
||||
rxelecidle_filter = _LowPassFilter(rxelecidle_i, self.rxelecidle, 256)
|
||||
self.submodules += rxelecidle_filter
|
||||
|
||||
# QPLL input clock
|
||||
self.qpllclk = Signal()
|
||||
|
@ -230,7 +240,7 @@ class K7LiteSATAPHYTRX(Module):
|
|||
# RX Byte and Word Alignment Attributes
|
||||
"p_ALIGN_COMMA_DOUBLE": "FALSE",
|
||||
"p_ALIGN_COMMA_ENABLE": ones(10),
|
||||
"p_ALIGN_COMMA_WORD": 2,
|
||||
"p_ALIGN_COMMA_WORD": 1,
|
||||
"p_ALIGN_MCOMMA_DET": "TRUE",
|
||||
"p_ALIGN_MCOMMA_VALUE": 0b1010000011,
|
||||
"p_ALIGN_PCOMMA_DET": "TRUE",
|
||||
|
@ -263,9 +273,9 @@ class K7LiteSATAPHYTRX(Module):
|
|||
"p_CLK_CORRECT_USE": "FALSE",
|
||||
"p_CLK_COR_SEQ_2_ENABLE": ones(4),
|
||||
"p_CLK_COR_SEQ_2_1": 0b0100000000,
|
||||
"p_CLK_COR_SEQ_2_2": 0,
|
||||
"p_CLK_COR_SEQ_2_3": 0,
|
||||
"p_CLK_COR_SEQ_2_4": 0,
|
||||
"p_CLK_COR_SEQ_2_2": 0b0000000000,
|
||||
"p_CLK_COR_SEQ_2_3": 0b0000000000,
|
||||
"p_CLK_COR_SEQ_2_4": 0b0000000000,
|
||||
|
||||
# RX Channel Bonding Attributes
|
||||
"p_CHAN_BOND_KEEP_ALIGN": "FALSE",
|
||||
|
@ -314,7 +324,7 @@ class K7LiteSATAPHYTRX(Module):
|
|||
"p_RX_CM_TRIM": 0b010,
|
||||
"p_RX_DEBUG_CFG": 0,
|
||||
"p_RX_OS_CFG": 0b10000000,
|
||||
"p_TERM_RCAL_CFG": 0,
|
||||
"p_TERM_RCAL_CFG": 0b10000,
|
||||
"p_TERM_RCAL_OVRD": 0,
|
||||
"p_TST_RSV": 0,
|
||||
"p_RX_CLK25_DIV": 6,
|
||||
|
@ -330,8 +340,8 @@ class K7LiteSATAPHYTRX(Module):
|
|||
# RX Buffer Attributes
|
||||
"p_RXBUF_ADDR_MODE": "FAST",
|
||||
"p_RXBUF_EIDLE_HI_CNT": 0b1000,
|
||||
"p_RXBUF_EIDLE_LO_CNT": 0,
|
||||
"p_RXBUF_EN": "TRUE",
|
||||
"p_RXBUF_EIDLE_LO_CNT": 0b0000,
|
||||
"p_RXBUF_EN": "FALSE",
|
||||
"p_RX_BUFFER_CFG": 0,
|
||||
"p_RXBUF_RESET_ON_CB_CHANGE": "TRUE",
|
||||
"p_RXBUF_RESET_ON_COMMAALIGN": "FALSE",
|
||||
|
@ -397,7 +407,7 @@ class K7LiteSATAPHYTRX(Module):
|
|||
"p_TRANS_TIME_RATE": 0x0e,
|
||||
|
||||
# TX Buffer Attributes
|
||||
"p_TXBUF_EN": "TRUE",
|
||||
"p_TXBUF_EN": "FALSE",
|
||||
"p_TXBUF_RESET_ON_RATE_CHANGE": "TRUE",
|
||||
"p_TXDLY_CFG": 0x1f,
|
||||
"p_TXDLY_LCFG": 0x030,
|
||||
|
@ -405,7 +415,7 @@ class K7LiteSATAPHYTRX(Module):
|
|||
"p_TXPH_CFG": 0x0780,
|
||||
"p_TXPHDLY_CFG": 0x084020,
|
||||
"p_TXPH_MONITOR_SEL": 0,
|
||||
"p_TX_XCLK_SEL": "TXOUT",
|
||||
"p_TX_XCLK_SEL": "TXUSR",
|
||||
|
||||
# FPGA TX Interface Attributes
|
||||
"p_TX_DATA_WIDTH": 20,
|
||||
|
@ -569,7 +579,7 @@ class K7LiteSATAPHYTRX(Module):
|
|||
# Receive Ports - CDR Ports
|
||||
i_RXCDRFREQRESET=0,
|
||||
i_RXCDRHOLD=0,
|
||||
o_RXCDRLOCK=rxcdrlock,
|
||||
#o_RXCDRLOCK=,
|
||||
i_RXCDROVRDEN=0,
|
||||
i_RXCDRRESET=0,
|
||||
i_RXCDRRESETRSV=0,
|
||||
|
@ -595,7 +605,7 @@ class K7LiteSATAPHYTRX(Module):
|
|||
i_RXPRBSCNTRESET=0,
|
||||
|
||||
# Receive Ports - RX Equalizer Ports
|
||||
i_RXDFEXYDEN=0,
|
||||
i_RXDFEXYDEN=1,
|
||||
i_RXDFEXYDHOLD=0,
|
||||
i_RXDFEXYDOVRDEN=0,
|
||||
|
||||
|
@ -610,12 +620,12 @@ class K7LiteSATAPHYTRX(Module):
|
|||
# Receive Ports - RX Buffer Bypass Ports
|
||||
i_RXBUFRESET=0,
|
||||
#o_RXBUFSTATUS=,
|
||||
i_RXDDIEN=0,
|
||||
i_RXDLYBYPASS=1,
|
||||
i_RXDDIEN=1,
|
||||
i_RXDLYBYPASS=0,
|
||||
i_RXDLYEN=0,
|
||||
i_RXDLYOVRDEN=0,
|
||||
i_RXDLYSRESET=0,
|
||||
#o_RXDLYSRESETDONE=0,
|
||||
i_RXDLYSRESET=rxdlyreset,
|
||||
o_RXDLYSRESETDONE=rxdlyresetdone,
|
||||
i_RXPHALIGN=0,
|
||||
#o_RXPHALIGNDONE=,
|
||||
i_RXPHALIGNEN=0,
|
||||
|
@ -627,7 +637,7 @@ class K7LiteSATAPHYTRX(Module):
|
|||
#o_RXSTATUS=,
|
||||
|
||||
# Receive Ports - RX Byte and Word Alignment Ports
|
||||
o_RXBYTEISALIGNED=self.rxbyteisaligned,
|
||||
#o_RXBYTEISALIGNED=,
|
||||
#o_RXBYTEREALIGN=,
|
||||
#o_RXCOMMADET=,
|
||||
i_RXCOMMADETEN=1,
|
||||
|
@ -651,7 +661,7 @@ class K7LiteSATAPHYTRX(Module):
|
|||
i_RXDFEAGCOVRDEN=0,
|
||||
i_RXDFECM1EN=0,
|
||||
i_RXDFELFHOLD=0,
|
||||
i_RXDFELFOVRDEN=1,
|
||||
i_RXDFELFOVRDEN=0,
|
||||
i_RXDFELPMRESET=0,
|
||||
i_RXDFETAP2HOLD=0,
|
||||
i_RXDFETAP2OVRDEN=0,
|
||||
|
@ -699,7 +709,7 @@ class K7LiteSATAPHYTRX(Module):
|
|||
i_GTRXRESET=self.gtrxreset,
|
||||
i_RXOOBRESET=0,
|
||||
i_RXPCSRESET=0,
|
||||
i_RXPMARESET=self.pmarxreset,
|
||||
i_RXPMARESET=0,
|
||||
|
||||
# Receive Ports - RX Margin Analysis ports
|
||||
i_RXLPMEN=0,
|
||||
|
@ -750,7 +760,7 @@ class K7LiteSATAPHYTRX(Module):
|
|||
|
||||
# TX Initialization and Reset Ports
|
||||
i_CFGRESET=0,
|
||||
i_GTTXRESET=self.gttxreset,
|
||||
i_GTTXRESET=gttxreset,
|
||||
#o_PCSRSVDOUT=,
|
||||
i_TXUSERRDY=txuserrdy,
|
||||
|
||||
|
@ -769,19 +779,19 @@ class K7LiteSATAPHYTRX(Module):
|
|||
# Transmit Ports - PCI Express Ports
|
||||
i_TXELECIDLE=txelecidle,
|
||||
i_TXMARGIN=0,
|
||||
i_TXRATE=txrate,
|
||||
i_TXRATE=0,
|
||||
i_TXSWING=0,
|
||||
|
||||
# Transmit Ports - Pattern Generator Ports
|
||||
i_TXPRBSFORCEERR=0,
|
||||
|
||||
# Transmit Ports - TX Buffer Bypass Ports
|
||||
i_TXDLYBYPASS=1,
|
||||
i_TXDLYBYPASS=0,
|
||||
i_TXDLYEN=0,
|
||||
i_TXDLYHOLD=0,
|
||||
i_TXDLYOVRDEN=0,
|
||||
i_TXDLYSRESET=0,
|
||||
#o_TXDLYSRESETDONE=,
|
||||
i_TXDLYSRESET=txdlyreset,
|
||||
o_TXDLYSRESETDONE=txdlyresetdone,
|
||||
i_TXDLYUPDOWN=0,
|
||||
i_TXPHALIGN=0,
|
||||
#o_TXPHALIGNDONE=txphaligndone,
|
||||
|
@ -815,7 +825,7 @@ class K7LiteSATAPHYTRX(Module):
|
|||
o_TXOUTCLK=self.txoutclk,
|
||||
#o_TXOUTCLKFABRIC=,
|
||||
#o_TXOUTCLKPCS=,
|
||||
i_TXOUTCLKSEL=0b11, # ??
|
||||
i_TXOUTCLKSEL=0b11,
|
||||
#o_TXRATEDONE=,
|
||||
# Transmit Ports - TX Gearbox Ports
|
||||
i_TXCHARISK=self.txcharisk,
|
||||
|
|
Loading…
Reference in a new issue