serwb/core/phy: move scrambler in phy, add link test, revert delay min/max checks

This commit is contained in:
Florent Kermarrec 2018-04-17 19:21:21 +02:00
parent ebfac36223
commit 20ccc9d82f
2 changed files with 86 additions and 30 deletions

View File

@ -2,13 +2,12 @@ from migen import *
from misoc.interconnect import stream from misoc.interconnect import stream
from artiq.gateware.serwb.scrambler import Scrambler, Descrambler
from artiq.gateware.serwb.packet import Packetizer, Depacketizer from artiq.gateware.serwb.packet import Packetizer, Depacketizer
from artiq.gateware.serwb.etherbone import Etherbone from artiq.gateware.serwb.etherbone import Etherbone
class SERWBCore(Module): class SERWBCore(Module):
def __init__(self, phy, clk_freq, mode, with_scrambling=False): def __init__(self, phy, clk_freq, mode):
# etherbone # etherbone
self.submodules.etherbone = etherbone = Etherbone(mode) self.submodules.etherbone = etherbone = Etherbone(mode)
@ -22,31 +21,14 @@ class SERWBCore(Module):
rx_fifo = stream.SyncFIFO([("data", 32)], 16) rx_fifo = stream.SyncFIFO([("data", 32)], 16)
self.submodules += tx_fifo, rx_fifo self.submodules += tx_fifo, rx_fifo
# scrambling
scrambler = Scrambler(enable=with_scrambling)
descrambler = Descrambler(enable=with_scrambling)
self.submodules += scrambler, descrambler
# modules connection # modules connection
self.comb += [ self.comb += [
# core --> phy # core --> phy
packetizer.source.connect(tx_fifo.sink), packetizer.source.connect(tx_fifo.sink),
tx_fifo.source.connect(scrambler.sink), tx_fifo.source.connect(phy.sink),
If(phy.init.ready,
If(scrambler.source.stb,
phy.serdes.tx_k.eq(scrambler.source.k),
phy.serdes.tx_d.eq(scrambler.source.d)
),
scrambler.source.ack.eq(phy.serdes.tx_ce)
),
# phy --> core # phy --> core
If(phy.init.ready, phy.source.connect(rx_fifo.sink),
descrambler.sink.stb.eq(phy.serdes.rx_ce),
descrambler.sink.k.eq(phy.serdes.rx_k),
descrambler.sink.d.eq(phy.serdes.rx_d)
),
descrambler.source.connect(rx_fifo.sink),
rx_fifo.source.connect(depacketizer.sink), rx_fifo.source.connect(depacketizer.sink),
# etherbone <--> core # etherbone <--> core

View File

@ -2,8 +2,10 @@ from migen import *
from migen.genlib.cdc import MultiReg, PulseSynchronizer from migen.genlib.cdc import MultiReg, PulseSynchronizer
from migen.genlib.misc import WaitTimer from migen.genlib.misc import WaitTimer
from misoc.interconnect import stream
from misoc.interconnect.csr import * from misoc.interconnect.csr import *
from artiq.gateware.serwb.scrambler import Scrambler, Descrambler
from artiq.gateware.serwb.kusphy import KUSSerdes from artiq.gateware.serwb.kusphy import KUSSerdes
from artiq.gateware.serwb.s7phy import S7Serdes from artiq.gateware.serwb.s7phy import S7Serdes
@ -110,7 +112,9 @@ class _SerdesMasterInit(Module):
serdes.tx_comma.eq(1) serdes.tx_comma.eq(1)
) )
fsm.act("CHECK_SAMPLING_WINDOW", fsm.act("CHECK_SAMPLING_WINDOW",
If((delay_max - delay_min) < taps//16, If((delay_min == 0) |
(delay_max == (taps - 1)) |
((delay_max - delay_min) < taps//16),
NextValue(delay_min_found, 0), NextValue(delay_min_found, 0),
NextValue(delay_max_found, 0), NextValue(delay_max_found, 0),
NextState("WAIT_STABLE") NextState("WAIT_STABLE")
@ -231,7 +235,9 @@ class _SerdesSlaveInit(Module, AutoCSR):
serdes.tx_idle.eq(1) serdes.tx_idle.eq(1)
) )
fsm.act("CHECK_SAMPLING_WINDOW", fsm.act("CHECK_SAMPLING_WINDOW",
If((delay_max - delay_min) < taps//16, If((delay_min == 0) |
(delay_max == (taps - 1)) |
((delay_max - delay_min) < taps//16),
NextValue(delay_min_found, 0), NextValue(delay_min_found, 0),
NextValue(delay_max_found, 0), NextValue(delay_max_found, 0),
NextState("WAIT_STABLE") NextState("WAIT_STABLE")
@ -289,18 +295,25 @@ class _SerdesControl(Module, AutoCSR):
self.delay_max = CSRStatus(9) self.delay_max = CSRStatus(9)
self.bitslip = CSRStatus(6) self.bitslip = CSRStatus(6)
self.scrambling_enable = CSRStorage()
self.prbs_error = Signal()
self.prbs_start = CSR()
self.prbs_cycles = CSRStorage(32)
self.prbs_errors = CSRStatus(32)
# # # # # #
if mode == "master": if mode == "master":
# In Master mode, reset is coming from CSR, # In Master mode, reset is coming from CSR,
# it resets the Master that will also reset # it resets the Master that will also reset
# the Slave by putting the link in idle. # the Slave by putting the link in idle.
self.comb += init.reset.eq(self.reset.re) self.sync += init.reset.eq(self.reset.re)
else: else:
# In Slave mode, reset is coming from link, # In Slave mode, reset is coming from link,
# Master reset the Slave by putting the link # Master reset the Slave by putting the link
# in idle. # in idle.
self.comb += [ self.sync += [
init.reset.eq(serdes.rx_idle), init.reset.eq(serdes.rx_idle),
serdes.reset.eq(serdes.rx_idle) serdes.reset.eq(serdes.rx_idle)
] ]
@ -315,20 +328,81 @@ class _SerdesControl(Module, AutoCSR):
self.bitslip.status.eq(init.bitslip) self.bitslip.status.eq(init.bitslip)
] ]
# prbs
prbs_cycles = Signal(32)
prbs_errors = self.prbs_errors.status
prbs_fsm = FSM(reset_state="IDLE")
self.submodules += prbs_fsm
prbs_fsm.act("IDLE",
NextValue(prbs_cycles, 0),
If(self.prbs_start.re,
NextValue(prbs_errors, 0),
NextState("CHECK")
)
)
prbs_fsm.act("CHECK",
NextValue(prbs_cycles, prbs_cycles + 1),
If(self.prbs_error,
NextValue(prbs_errors, prbs_errors + 1),
),
If(prbs_cycles == self.prbs_cycles.storage,
NextState("IDLE")
)
)
class SERWBPHY(Module, AutoCSR): class SERWBPHY(Module, AutoCSR):
def __init__(self, device, pads, mode="master", phy_width=8): def __init__(self, device, pads, mode="master", init_timeout=2**14):
self.sink = sink = stream.Endpoint([("data", 32)])
self.source = source = stream.Endpoint([("data", 32)])
assert mode in ["master", "slave"] assert mode in ["master", "slave"]
if device[:4] == "xcku": if device[:4] == "xcku":
taps = 512 taps = 512
self.submodules.serdes = KUSSerdes(pads, mode, phy_width) self.submodules.serdes = KUSSerdes(pads, mode)
elif device[:4] == "xc7a": elif device[:4] == "xc7a":
taps = 32 taps = 32
self.submodules.serdes = S7Serdes(pads, mode, phy_width) self.submodules.serdes = S7Serdes(pads, mode)
else: else:
raise NotImplementedError raise NotImplementedError
if mode == "master": if mode == "master":
self.submodules.init = _SerdesMasterInit(self.serdes, taps) self.submodules.init = _SerdesMasterInit(self.serdes, taps, init_timeout)
else: else:
self.submodules.init = _SerdesSlaveInit(self.serdes, taps) self.submodules.init = _SerdesSlaveInit(self.serdes, taps, init_timeout)
self.submodules.control = _SerdesControl(self.serdes, self.init, mode) self.submodules.control = _SerdesControl(self.serdes, self.init, mode)
# scrambling
scrambler = Scrambler()
descrambler = Descrambler()
self.submodules += scrambler, descrambler
self.comb += [
scrambler.enable.eq(self.control.scrambling_enable.storage),
descrambler.enable.eq(self.control.scrambling_enable.storage)
]
# tx dataflow
self.comb += \
If(self.init.ready,
sink.connect(scrambler.sink),
scrambler.source.ack.eq(self.serdes.tx_ce),
If(scrambler.source.stb,
self.serdes.tx_d.eq(scrambler.source.d),
self.serdes.tx_k.eq(scrambler.source.k)
)
)
# rx dataflow
self.comb += [
If(self.init.ready,
descrambler.sink.stb.eq(self.serdes.rx_ce),
descrambler.sink.d.eq(self.serdes.rx_d),
descrambler.sink.k.eq(self.serdes.rx_k),
descrambler.source.connect(source)
),
# For PRBS test we are using the scrambler/descrambler as PRBS,
# sending 0 to the scrambler and checking that descrambler
# output is always 0.
self.control.prbs_error.eq(
descrambler.source.stb &
descrambler.source.ack &
(descrambler.source.data != 0))
]