mirror of
https://github.com/enjoy-digital/usb3_pipe.git
synced 2025-01-04 10:18:41 +08:00
usb3_pipe/lfps: document and make LFPSChecker/Generator generic.
This commit is contained in:
parent
34d201e208
commit
1147f23080
@ -74,7 +74,7 @@ class TestLFPS(unittest.TestCase):
|
||||
|
||||
def test_lfps_generator(self):
|
||||
def lfps_generator(dut):
|
||||
yield dut.polling.eq(1)
|
||||
yield dut.generate.eq(1)
|
||||
for i in range(int(1e4)):
|
||||
yield
|
||||
dut.run = False
|
||||
@ -100,7 +100,7 @@ class TestLFPS(unittest.TestCase):
|
||||
sys_clk_freq = 100e6
|
||||
lfps_clk_freq = 25e6
|
||||
|
||||
dut = lfps.LFPSGenerator(sys_clk_freq, lfps_clk_freq)
|
||||
dut = lfps.LFPSGenerator(lfps.PollingLFPS, sys_clk_freq, lfps_clk_freq)
|
||||
dut.run = True
|
||||
generators = [
|
||||
lfps_generator(dut),
|
||||
|
@ -36,7 +36,7 @@ class USB3PIPE(Module):
|
||||
source = self.source
|
||||
|
||||
# LFPS -------------------------------------------------------------------------------------
|
||||
lfps = LFPSUnit(sys_clk_freq=sys_clk_freq, serdes=serdes)
|
||||
lfps = LFPSUnit(serdes=serdes, sys_clk_freq=sys_clk_freq)
|
||||
self.submodules.lfps = lfps
|
||||
|
||||
# TS----------------------------------------------------------------------------------------
|
||||
|
@ -1,6 +1,23 @@
|
||||
# This file is Copyright (c) 2019 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||
# License: BSD
|
||||
|
||||
# LFPS is the first signaling to happen during the initialization of the USB3.0 link.
|
||||
|
||||
# LFPS allows partners to exchange Out Of Band (OOB) controls/commands and consists of bursts where
|
||||
# a "slow" clock is generated (between 10M-50MHz) for a specific duration and with a specific repeat
|
||||
# period. After the burst, the transceiver is put in electrical idle mode (same electrical level on
|
||||
# P/N pairs while in nominal mode P/N pairs always have an opposite level):
|
||||
#
|
||||
# Transceiver level/mode: _=0, -=1 x=electrical idle
|
||||
# |-_-_-_-xxxxxxxxxxxxxxxxxxxx|-_-_-_-xxxxxxxxxxxxxxxxxxxx|...
|
||||
# |<burst> |<burst> |...
|
||||
# |<-----repeat period------->|<--------period----------->|...
|
||||
#
|
||||
# A LFPS pattern is identified by a burst duration and repeat period.
|
||||
#
|
||||
# To be able generate and receive LFPS, a transceiver needs to be able put its TX in electrical idle
|
||||
# and to detect RX electrical idle.
|
||||
|
||||
from math import ceil
|
||||
|
||||
from migen import *
|
||||
@ -13,6 +30,7 @@ lfps_clk_freq_min = 1/100e-9
|
||||
lfps_clk_freq_max = 1/20e-9
|
||||
|
||||
class LFPSTiming:
|
||||
"""LPFS timings with typical, minimum and maximum timing values."""
|
||||
def __init__(self, t_typ=None, t_min=None, t_max=None):
|
||||
self.t_typ = t_typ
|
||||
self.t_min = t_min
|
||||
@ -22,6 +40,7 @@ class LFPSTiming:
|
||||
self.range = (t_min, t_max)
|
||||
|
||||
class LFPS:
|
||||
"""LPFS patterns with burst and repeat timings."""
|
||||
def __init__(self, burst, repeat=None, cycles=None):
|
||||
self.burst = burst
|
||||
self.repeat = repeat
|
||||
@ -30,7 +49,7 @@ class LFPS:
|
||||
def ns_to_cycles(clk_freq, t):
|
||||
return ceil(t*clk_freq)
|
||||
|
||||
# LFPS Definitions ---------------------------------------------------------------------------------
|
||||
# LFPS Patterns ------------------------------------------------------------------------------------
|
||||
|
||||
PollingLFPSBurst = LFPSTiming(t_typ=1.0e-6, t_min=0.6e-6, t_max=1.4e-6)
|
||||
PollingLFPSRepeat = LFPSTiming(t_typ=10.0e-6, t_min=6.0e-6, t_max=14.0e-6)
|
||||
@ -42,9 +61,17 @@ ResetLFPS = LFPS(burst=ResetLFPSBurst)
|
||||
# LFPS Checker -------------------------------------------------------------------------------------
|
||||
|
||||
class LFPSChecker(Module):
|
||||
def __init__(self, sys_clk_freq):
|
||||
self.idle = Signal() # i
|
||||
self.polling = Signal() # o
|
||||
"""LFPS Checker
|
||||
|
||||
Generic LFPS checker.
|
||||
|
||||
This module is able to detect a specific LFPS pattern by analyzing the RX electrical idle signal
|
||||
of the transceiver. It generates the pattern internally and try lock it to the RX electical idle
|
||||
signal. When locked a detection is reported.
|
||||
"""
|
||||
def __init__(self, lfps_pattern, sys_clk_freq):
|
||||
self.idle = Signal() # i
|
||||
self.detect = Signal() # o
|
||||
|
||||
# # #
|
||||
|
||||
@ -52,9 +79,9 @@ class LFPSChecker(Module):
|
||||
idle = Signal()
|
||||
self.specials += MultiReg(self.idle, idle)
|
||||
|
||||
# Polling LFPS Detection -------------------------------------------------------------------
|
||||
burst_cycles = ns_to_cycles(sys_clk_freq, PollingLFPS.burst.t_typ)
|
||||
repeat_cycles = ns_to_cycles(sys_clk_freq, PollingLFPS.repeat.t_typ)
|
||||
# Polling LFPS Detection ------------------------------------------------------------------
|
||||
burst_cycles = ns_to_cycles(sys_clk_freq, lfps_pattern.burst.t_typ)
|
||||
repeat_cycles = ns_to_cycles(sys_clk_freq, lfps_pattern.repeat.t_typ)
|
||||
self.count = count = Signal(max=max(burst_cycles, repeat_cycles))
|
||||
self.found = found = Signal()
|
||||
|
||||
@ -71,7 +98,7 @@ class LFPSChecker(Module):
|
||||
NextValue(count, count - 1)
|
||||
),
|
||||
If(found & (idle == 0),
|
||||
self.polling.eq(1),
|
||||
self.detect.eq(1),
|
||||
NextValue(found, 0)
|
||||
),
|
||||
)
|
||||
@ -89,8 +116,8 @@ class LFPSChecker(Module):
|
||||
class LFPSBurstGenerator(Module):
|
||||
"""LFPS Burst Generator
|
||||
|
||||
Generate a LFPS Burst of configurable length on the TX lanes. The LFPS clock is generated by
|
||||
sending a alternating ones/zeroes data pattern on the parallel interface of the transceiver.
|
||||
Generate a LFPS burst of configurable length on the TX lane. The LFPS clock is generated by
|
||||
sending an alternating ones/zeroes data pattern on the parallel interface of the transceiver.
|
||||
"""
|
||||
def __init__(self, sys_clk_freq, lfps_clk_freq):
|
||||
# Control
|
||||
@ -142,14 +169,13 @@ class LFPSBurstGenerator(Module):
|
||||
class LFPSGenerator(Module):
|
||||
"""LFPS Generator
|
||||
|
||||
Generate LFPS signals on the TX lanes from simple user controls (User just have to sets LFPS
|
||||
control signal to 1 to generate a specific LFPS, this module will handle LFPS clock genration,
|
||||
LFPS Burst length and repeat).
|
||||
Generate a specific LFPS pattern on the TX lane. This module handles LFPS clock generation, LFPS
|
||||
burst generation and repetition.
|
||||
"""
|
||||
def __init__(self, sys_clk_freq, lfps_clk_freq):
|
||||
def __init__(self, lfps_pattern, sys_clk_freq, lfps_clk_freq):
|
||||
# Control
|
||||
self.polling = Signal() # i
|
||||
self.count = Signal(16) # o
|
||||
self.generate = Signal() # i
|
||||
self.count = Signal(16) # o
|
||||
|
||||
# Transceiver
|
||||
self.tx_idle = Signal() # o
|
||||
@ -166,11 +192,11 @@ class LFPSGenerator(Module):
|
||||
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
|
||||
fsm.act("IDLE",
|
||||
self.tx_idle.eq(0),
|
||||
If(self.polling,
|
||||
If(self.generate,
|
||||
self.tx_idle.eq(1),
|
||||
NextValue(burst_generator.start, 1),
|
||||
NextValue(burst_generator.length, int(sys_clk_freq*PollingLFPSBurst.t_typ)),
|
||||
NextValue(burst_repeat_count, int(sys_clk_freq*PollingLFPSRepeat.t_typ)),
|
||||
NextValue(burst_generator.length, int(sys_clk_freq*lfps_pattern.burst.t_typ)),
|
||||
NextValue(burst_repeat_count, int(sys_clk_freq*lfps_pattern.repeat.t_typ)),
|
||||
NextState("RUN")
|
||||
).Else(
|
||||
NextValue(self.count, 0)
|
||||
@ -190,7 +216,11 @@ class LFPSGenerator(Module):
|
||||
# LFPS Unit ----------------------------------------------------------------------------------------
|
||||
|
||||
class LFPSUnit(Module):
|
||||
def __init__(self, sys_clk_freq, serdes):
|
||||
"""LFPS Unit
|
||||
|
||||
Detect/generate the LFPS patterns required for a USB3.0 link with simple control/status signals.
|
||||
"""
|
||||
def __init__(self, serdes, sys_clk_freq, lfps_clk_freq=25e6):
|
||||
self.rx_polling = Signal() # o
|
||||
self.tx_idle = Signal() # i
|
||||
self.tx_polling = Signal() # i
|
||||
@ -198,22 +228,22 @@ class LFPSUnit(Module):
|
||||
|
||||
# # #
|
||||
|
||||
# LFPS Checker -----------------------------------------------------------------------------
|
||||
checker = LFPSChecker(sys_clk_freq=sys_clk_freq)
|
||||
self.submodules += checker
|
||||
self.comb += checker.idle.eq(serdes.rx_idle)
|
||||
self.comb += self.rx_polling.eq(checker.polling)
|
||||
# LFPS Checkers ----------------------------------------------------------------------------
|
||||
polling_checker = LFPSChecker(PollingLFPS, sys_clk_freq)
|
||||
self.submodules += polling_checker
|
||||
self.comb += polling.checker.idle.eq(serdes.rx_idle)
|
||||
self.comb += self.rx_polling.eq(polling_checker.detect)
|
||||
|
||||
# LFPS Generator ---------------------------------------------------------------------------
|
||||
generator = LFPSGenerator(sys_clk_freq=sys_clk_freq, lfps_clk_freq=25e6)
|
||||
self.submodules += generator
|
||||
# LFPS Generators --------------------------------------------------------------------------
|
||||
polling_generator = LFPSGenerator(PollingLFPS, sys_clk_freq, lfps_clk_freq)
|
||||
self.submodules += polling_generator
|
||||
self.comb += [
|
||||
If(self.tx_polling,
|
||||
generator.polling.eq(1),
|
||||
serdes.tx_idle.eq(generator.tx_idle),
|
||||
serdes.tx_pattern.eq(generator.tx_pattern)
|
||||
polling_generator.generate.eq(1),
|
||||
serdes.tx_idle.eq(polling_generator.tx_idle),
|
||||
serdes.tx_pattern.eq(polling_generator.tx_pattern)
|
||||
).Else(
|
||||
serdes.tx_idle.eq(self.tx_idle)
|
||||
),
|
||||
self.tx_count.eq(generator.count)
|
||||
self.tx_count.eq(polling_generator.count)
|
||||
]
|
||||
|
Loading…
x
Reference in New Issue
Block a user