gateware/serwb: add scrambling, reduce cdc fifo depth

This commit is contained in:
Florent Kermarrec 2018-01-03 17:32:18 +01:00
parent 7f4756a869
commit 907af25a69
5 changed files with 163 additions and 33 deletions

View File

@ -2,38 +2,54 @@ from migen import *
from misoc.interconnect import stream from misoc.interconnect import stream
from artiq.gateware.serwb.packet import Depacketizer, Packetizer from artiq.gateware.serwb.scrambler import Scrambler, Descrambler
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): def __init__(self, phy, clk_freq, mode, with_scrambling=False):
# etherbone
self.submodules.etherbone = etherbone = Etherbone(mode) self.submodules.etherbone = etherbone = Etherbone(mode)
# packetizer / depacketizer
depacketizer = Depacketizer(clk_freq) depacketizer = Depacketizer(clk_freq)
packetizer = Packetizer() packetizer = Packetizer()
self.submodules += depacketizer, packetizer self.submodules += depacketizer, packetizer
tx_cdc = stream.AsyncFIFO([("data", 32)], 32)
tx_cdc = ClockDomainsRenamer({"write": "sys", "read": "serwb_serdes"})(tx_cdc)
self.submodules += tx_cdc
rx_cdc = stream.AsyncFIFO([("data", 32)], 32)
rx_cdc = ClockDomainsRenamer({"write": "serwb_serdes", "read": "sys"})(rx_cdc)
self.submodules += rx_cdc
self.comb += [
# core <--> etherbone
depacketizer.source.connect(etherbone.sink),
etherbone.source.connect(packetizer.sink),
# core --> serdes # clock domain crossing
tx_cdc = stream.AsyncFIFO([("data", 32)], 16)
tx_cdc = ClockDomainsRenamer({"write": "sys", "read": phy.cd})(tx_cdc)
rx_cdc = stream.AsyncFIFO([("data", 32)], 16)
rx_cdc = ClockDomainsRenamer({"write": phy.cd, "read": "sys"})(rx_cdc)
self.submodules += tx_cdc, rx_cdc
# scrambling
scrambler = ClockDomainsRenamer(phy.cd)(Scrambler(enable=with_scrambling))
descrambler = ClockDomainsRenamer(phy.cd)(Descrambler(enable=with_scrambling))
self.submodules += scrambler, descrambler
# modules connection
self.comb += [
# core --> phy
packetizer.source.connect(tx_cdc.sink), packetizer.source.connect(tx_cdc.sink),
tx_cdc.source.connect(scrambler.sink),
If(phy.init.ready, If(phy.init.ready,
If(tx_cdc.source.stb, If(scrambler.source.stb,
phy.serdes.tx_data.eq(tx_cdc.source.data) phy.serdes.tx_k.eq(scrambler.source.k),
phy.serdes.tx_d.eq(scrambler.source.d)
), ),
tx_cdc.source.ack.eq(1) scrambler.source.ack.eq(1)
), ),
# serdes --> core # phy --> core
rx_cdc.sink.stb.eq(phy.init.ready), descrambler.sink.stb.eq(phy.init.ready),
rx_cdc.sink.data.eq(phy.serdes.rx_data), descrambler.sink.k.eq(phy.serdes.rx_k),
descrambler.sink.d.eq(phy.serdes.rx_d),
descrambler.source.connect(rx_cdc.sink),
rx_cdc.source.connect(depacketizer.sink), rx_cdc.source.connect(depacketizer.sink),
# etherbone <--> core
depacketizer.source.connect(etherbone.sink),
etherbone.source.connect(packetizer.sink)
] ]

View File

@ -8,8 +8,10 @@ from misoc.cores.code_8b10b import Encoder, Decoder
class KUSSerdes(Module): class KUSSerdes(Module):
def __init__(self, pll, pads, mode="master"): def __init__(self, pll, pads, mode="master"):
self.tx_data = Signal(32) self.tx_k = Signal(4)
self.rx_data = Signal(32) self.tx_d = Signal(32)
self.rx_k = Signal(4)
self.rx_d = Signal(32)
self.tx_idle = Signal() self.tx_idle = Signal()
self.tx_comma = Signal() self.tx_comma = Signal()
@ -111,10 +113,14 @@ class KUSSerdes(Module):
self.encoder.k[0].eq(1), self.encoder.k[0].eq(1),
self.encoder.d[0].eq(0xbc) self.encoder.d[0].eq(0xbc)
).Else( ).Else(
self.encoder.d[0].eq(self.tx_data[0:8]), self.encoder.k[0].eq(self.tx_k[0]),
self.encoder.d[1].eq(self.tx_data[8:16]), self.encoder.k[1].eq(self.tx_k[1]),
self.encoder.d[2].eq(self.tx_data[16:24]), self.encoder.k[2].eq(self.tx_k[2]),
self.encoder.d[3].eq(self.tx_data[24:32]) self.encoder.k[3].eq(self.tx_k[3]),
self.encoder.d[0].eq(self.tx_d[0:8]),
self.encoder.d[1].eq(self.tx_d[8:16]),
self.encoder.d[2].eq(self.tx_d[16:24]),
self.encoder.d[3].eq(self.tx_d[24:32])
) )
] ]
self.sync.serwb_serdes += \ self.sync.serwb_serdes += \
@ -217,7 +223,8 @@ class KUSSerdes(Module):
self.decoders[1].input.eq(self.rx_bitslip.o[10:20]), self.decoders[1].input.eq(self.rx_bitslip.o[10:20]),
self.decoders[2].input.eq(self.rx_bitslip.o[20:30]), self.decoders[2].input.eq(self.rx_bitslip.o[20:30]),
self.decoders[3].input.eq(self.rx_bitslip.o[30:40]), self.decoders[3].input.eq(self.rx_bitslip.o[30:40]),
self.rx_data.eq(Cat(*[self.decoders[i].d for i in range(4)])), self.rx_k.eq(Cat(*[self.decoders[i].k for i in range(4)])),
self.rx_d.eq(Cat(*[self.decoders[i].d for i in range(4)])),
rx_idle.eq(self.rx_bitslip.o == 0), rx_idle.eq(self.rx_bitslip.o == 0),
rx_comma.eq(((self.decoders[0].d == 0xbc) & (self.decoders[0].k == 1)) & rx_comma.eq(((self.decoders[0].d == 0xbc) & (self.decoders[0].k == 1)) &
((self.decoders[1].d == 0x00) & (self.decoders[1].k == 0)) & ((self.decoders[1].d == 0x00) & (self.decoders[1].k == 0)) &

View File

@ -376,6 +376,7 @@ class SERWBPLL(Module):
class SERWBPHY(Module, AutoCSR): class SERWBPHY(Module, AutoCSR):
cd = "serwb_serdes"
def __init__(self, device, pll, pads, mode="master"): def __init__(self, device, pll, pads, mode="master"):
assert mode in ["master", "slave"] assert mode in ["master", "slave"]
if device[:4] == "xcku": if device[:4] == "xcku":

View File

@ -8,8 +8,10 @@ from misoc.cores.code_8b10b import Encoder, Decoder
class S7Serdes(Module): class S7Serdes(Module):
def __init__(self, pll, pads, mode="master"): def __init__(self, pll, pads, mode="master"):
self.tx_data = Signal(32) self.tx_k = Signal(4)
self.rx_data = Signal(32) self.tx_d = Signal(32)
self.rx_k = Signal(4)
self.rx_d = Signal(32)
self.tx_idle = Signal() self.tx_idle = Signal()
self.tx_comma = Signal() self.tx_comma = Signal()
@ -99,10 +101,14 @@ class S7Serdes(Module):
self.encoder.k[0].eq(1), self.encoder.k[0].eq(1),
self.encoder.d[0].eq(0xbc) self.encoder.d[0].eq(0xbc)
).Else( ).Else(
self.encoder.d[0].eq(self.tx_data[0:8]), self.encoder.k[0].eq(self.tx_k[0]),
self.encoder.d[1].eq(self.tx_data[8:16]), self.encoder.k[1].eq(self.tx_k[1]),
self.encoder.d[2].eq(self.tx_data[16:24]), self.encoder.k[2].eq(self.tx_k[2]),
self.encoder.d[3].eq(self.tx_data[24:32]) self.encoder.k[3].eq(self.tx_k[3]),
self.encoder.d[0].eq(self.tx_d[0:8]),
self.encoder.d[1].eq(self.tx_d[8:16]),
self.encoder.d[2].eq(self.tx_d[16:24]),
self.encoder.d[3].eq(self.tx_d[24:32])
) )
] ]
self.sync.serwb_serdes += \ self.sync.serwb_serdes += \
@ -213,7 +219,8 @@ class S7Serdes(Module):
self.decoders[1].input.eq(self.rx_bitslip.o[10:20]), self.decoders[1].input.eq(self.rx_bitslip.o[10:20]),
self.decoders[2].input.eq(self.rx_bitslip.o[20:30]), self.decoders[2].input.eq(self.rx_bitslip.o[20:30]),
self.decoders[3].input.eq(self.rx_bitslip.o[30:40]), self.decoders[3].input.eq(self.rx_bitslip.o[30:40]),
self.rx_data.eq(Cat(*[self.decoders[i].d for i in range(4)])), self.rx_k.eq(Cat(*[self.decoders[i].k for i in range(4)])),
self.rx_d.eq(Cat(*[self.decoders[i].d for i in range(4)])),
rx_idle.eq(self.rx_bitslip.o == 0), rx_idle.eq(self.rx_bitslip.o == 0),
rx_comma.eq(((self.decoders[0].d == 0xbc) & (self.decoders[0].k == 1)) & rx_comma.eq(((self.decoders[0].d == 0xbc) & (self.decoders[0].k == 1)) &
((self.decoders[1].d == 0x00) & (self.decoders[1].k == 0)) & ((self.decoders[1].d == 0x00) & (self.decoders[1].k == 0)) &

View File

@ -0,0 +1,99 @@
from functools import reduce
from operator import xor
from migen import *
from misoc.interconnect import stream
def K(x, y):
return (y << 5) | x
@ResetInserter()
class _Scrambler(Module):
def __init__(self, n_io, n_state=23, taps=[17, 22]):
self.i = Signal(n_io)
self.o = Signal(n_io)
# # #
state = Signal(n_state, reset=1)
curval = [state[i] for i in range(n_state)]
for i in reversed(range(n_io)):
flip = reduce(xor, [curval[tap] for tap in taps])
self.comb += self.o[i].eq(flip ^ self.i[i])
curval.insert(0, flip)
curval.pop()
self.sync += state.eq(Cat(*curval[:n_state]))
class Scrambler(Module):
def __init__(self, sync_interval=1024, enable=True):
self.sink = sink = stream.Endpoint([("data", 32)])
self.source = source = stream.Endpoint([("d", 32), ("k", 4)])
# # #
if enable:
# scrambler
scrambler = _Scrambler(32)
self.submodules += scrambler
self.comb += scrambler.i.eq(sink.data)
# insert K.29.7 as sync character
# every sync_interval cycles
count = Signal(max=sync_interval)
self.sync += count.eq(count + 1)
self.comb += [
If(count == 0,
scrambler.reset.eq(1),
source.stb.eq(1),
source.k[0].eq(1),
source.d[:8].eq(K(29, 7))
).Else(
sink.ack.eq(source.ack),
source.stb.eq(sink.stb),
source.d.eq(scrambler.o)
)
]
else:
self.comb += [
sink.connect(source, omit={"data"}),
source.k.eq(0b0000),
source.d.eq(sink.data)
]
class Descrambler(Module):
def __init__(self, enable=True):
self.sink = sink = stream.Endpoint([("d", 32), ("k", 4)])
self.source = source = stream.Endpoint([("data", 32)])
# # #
if enable:
# descrambler
descrambler = _Scrambler(32)
self.submodules += descrambler
self.comb += descrambler.i.eq(sink.d)
# detect K29.7 and synchronize descrambler
self.comb += [
descrambler.reset.eq(0),
If((sink.k[0] == 1) &
(sink.d[:8] == K(29,7)),
sink.ack.eq(1),
descrambler.reset.eq(1)
).Else(
sink.ack.eq(source.ack),
source.stb.eq(sink.stb),
source.data.eq(descrambler.o)
)
]
else:
self.comb += [
sink.connect(source, omit={"d", "k"}),
source.data.eq(sink.d)
]