From 7296a76f180a742682ddcd63892e3db0379b7efd Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 8 Jun 2018 12:15:00 +0200 Subject: [PATCH] serwb: move common datapath code to datapath.py, simplify flow control --- artiq/gateware/serwb/datapath.py | 198 +++++++++++++++++++++++++++++++ artiq/gateware/serwb/genphy.py | 155 ++++++------------------ artiq/gateware/serwb/kuserdes.py | 110 ++++------------- artiq/gateware/serwb/phy.py | 48 +++----- artiq/gateware/serwb/s7serdes.py | 109 ++++------------- 5 files changed, 297 insertions(+), 323 deletions(-) create mode 100644 artiq/gateware/serwb/datapath.py diff --git a/artiq/gateware/serwb/datapath.py b/artiq/gateware/serwb/datapath.py new file mode 100644 index 000000000..9d7f0bb19 --- /dev/null +++ b/artiq/gateware/serwb/datapath.py @@ -0,0 +1,198 @@ +from migen import * +from migen.genlib.io import * +from migen.genlib.misc import BitSlip, WaitTimer + +from misoc.interconnect import stream +from misoc.cores.code_8b10b import Encoder, Decoder + +from artiq.gateware.serwb.scrambler import Scrambler, Descrambler + + +def K(x, y): + return (y << 5) | x + + +class _8b10bEncoder(Module): + def __init__(self): + self.sink = sink = stream.Endpoint([("d", 32), ("k", 4)]) + self.source = source = stream.Endpoint([("data", 40)]) + + # # # + + encoder = CEInserter()(Encoder(4, True)) + self.submodules += encoder + + # control + self.comb += [ + source.stb.eq(sink.stb), + sink.ack.eq(source.ack), + encoder.ce.eq(source.stb & source.ack) + ] + + # datapath + for i in range(4): + self.comb += [ + encoder.k[i].eq(sink.k[i]), + encoder.d[i].eq(sink.d[8*i:8*(i+1)]), + source.data[10*i:10*(i+1)].eq(encoder.output[i]) + ] + + +class _8b10bDecoder(Module): + def __init__(self): + self.sink = sink = stream.Endpoint([("data", 40)]) + self.source = source = stream.Endpoint([("d", 32), ("k", 4)]) + + # # # + + decoders = [CEInserter()(Decoder(True)) for _ in range(4)] + self.submodules += decoders + + # control + self.comb += [ + source.stb.eq(sink.stb), + sink.ack.eq(source.ack) + ] + self.comb += [decoders[i].ce.eq(source.stb & source.ack) for i in range(4)] + + # datapath + for i in range(4): + self.comb += [ + decoders[i].input.eq(sink.data[10*i:10*(i+1)]), + source.k[i].eq(decoders[i].k), + source.d[8*i:8*(i+1)].eq(decoders[i].d) + ] + + +class _Bitslip(Module): + def __init__(self): + self.value = value = Signal(6) + self.sink = sink = stream.Endpoint([("data", 40)]) + self.source = source = stream.Endpoint([("data", 40)]) + + # # # + + bitslip = CEInserter()(BitSlip(40)) + self.submodules += bitslip + + # control + self.comb += [ + source.stb.eq(sink.stb), + sink.ack.eq(source.ack), + bitslip.value.eq(value), + bitslip.ce.eq(source.stb & source.ack) + ] + + # datapath + self.comb += [ + bitslip.i.eq(sink.data), + source.data.eq(bitslip.o) + ] + + +class TXDatapath(Module): + def __init__(self, phy_dw, with_scrambling=True): + self.idle = idle = Signal() + self.comma = comma = Signal() + self.sink = sink = stream.Endpoint([("data", 32)]) + self.source = source = stream.Endpoint([("data", phy_dw)]) + + # # # + + # scrambler + if with_scrambling: + self.submodules.scrambler = scrambler = Scrambler() + + # line coding + self.submodules.encoder = encoder = _8b10bEncoder() + + # converter + self.submodules.converter = converter = stream.Converter(40, phy_dw) + + # dataflow + if with_scrambling: + self.comb += [ + sink.connect(scrambler.sink), + If(comma, + encoder.sink.stb.eq(1), + encoder.sink.k.eq(1), + encoder.sink.d.eq(K(28,5)) + ).Else( + scrambler.source.connect(encoder.sink) + ) + ] + else: + self.comb += [ + If(comma, + encoder.sink.stb.eq(1), + encoder.sink.k.eq(1), + encoder.sink.d.eq(K(28,5)) + ).Else( + sink.connect(encoder.sink, omit={"data"}), + encoder.sink.d.eq(sink.data) + ), + ] + self.comb += [ + If(idle, + converter.sink.stb.eq(1), + converter.sink.data.eq(0) + ).Else( + encoder.source.connect(converter.sink), + ), + converter.source.connect(source) + ] + + +class RXDatapath(Module): + def __init__(self, phy_dw, with_scrambling=True): + self.bitslip_value = bitslip_value = Signal(6) + self.sink = sink = stream.Endpoint([("data", phy_dw)]) + self.source = source = stream.Endpoint([("data", 32)]) + self.idle = idle = Signal() + self.comma = comma = Signal() + + # # # + + # converter + self.submodules.converter = converter = stream.Converter(phy_dw, 40) + + # bitslip + self.submodules.bitslip = bitslip = _Bitslip() + self.comb += bitslip.value.eq(bitslip_value) + + # line coding + self.submodules.decoder = decoder = _8b10bDecoder() + + # descrambler + if with_scrambling: + self.submodules.descrambler = descrambler = Descrambler() + + # dataflow + self.comb += [ + sink.connect(converter.sink), + converter.source.connect(bitslip.sink), + bitslip.source.connect(decoder.sink) + ] + if with_scrambling: + self.comb += [ + decoder.source.connect(descrambler.sink), + descrambler.source.connect(source) + ] + else: + self.comb += [ + decoder.source.connect(source, omit={"d", "k"}), + source.data.eq(decoder.source.d) + ] + + # idle decoding + idle_timer = WaitTimer(256) + self.submodules += idle_timer + self.comb += [ + idle_timer.wait.eq(1), + idle.eq(idle_timer.done & ((converter.source.data == 0) | (converter.source.data == (2**40-1)))) + ] + # comma decoding + self.sync += \ + If(decoder.source.stb, + comma.eq((decoder.source.k == 1) & (decoder.source.d == K(28, 5))) + ) diff --git a/artiq/gateware/serwb/genphy.py b/artiq/gateware/serwb/genphy.py index 3c385b0d3..e3d2d3fbd 100644 --- a/artiq/gateware/serwb/genphy.py +++ b/artiq/gateware/serwb/genphy.py @@ -4,13 +4,8 @@ from migen.genlib.misc import BitSlip, WaitTimer from misoc.interconnect import stream from misoc.interconnect.csr import * -from misoc.cores.code_8b10b import Encoder, Decoder -from artiq.gateware.serwb.scrambler import Scrambler, Descrambler - - -def K(x, y): - return (y << 5) | x +from artiq.gateware.serwb.datapath import TXDatapath, RXDatapath class _SerdesClocking(Module): @@ -30,59 +25,33 @@ class _SerdesClocking(Module): class _SerdesTX(Module): - def __init__(self, pads, mode="master"): + def __init__(self, pads): # Control self.idle = idle = Signal() self.comma = comma = Signal() # Datapath - self.ce = ce = Signal() - self.k = k = Signal(4) - self.d = d = Signal(32) + self.sink = sink = stream.Endpoint([("data", 32)]) # # # - # 8b10b encoder - self.submodules.encoder = encoder = CEInserter()(Encoder(4, True)) - self.comb += encoder.ce.eq(ce) - - # 40 --> 1 converter - converter = stream.Converter(40, 1) - self.submodules += converter + # Datapath + self.submodules.datapath = datapath = TXDatapath(1) self.comb += [ - converter.sink.stb.eq(1), - converter.source.ack.eq(1), - # Enable pipeline when converter accepts the 40 bits - ce.eq(converter.sink.ack), - # If not idle, connect encoder to converter - If(~idle, - converter.sink.data.eq(Cat(*[encoder.output[i] for i in range(4)])) - ), - # If comma, send K28.5 - If(comma, - encoder.k[0].eq(1), - encoder.d[0].eq(K(28,5)), - # Else connect TX to encoder - ).Else( - encoder.k[0].eq(k[0]), - encoder.k[1].eq(k[1]), - encoder.k[2].eq(k[2]), - encoder.k[3].eq(k[3]), - encoder.d[0].eq(d[0:8]), - encoder.d[1].eq(d[8:16]), - encoder.d[2].eq(d[16:24]), - encoder.d[3].eq(d[24:32]) - ) + sink.connect(datapath.sink), + datapath.source.ack.eq(1), + datapath.idle.eq(idle), + datapath.comma.eq(comma) ] - # Data output (on rising edge of sys_clk) + # Output data (on rising edge of sys_clk) data = Signal() - self.sync += data.eq(converter.source.data) + self.sync += data.eq(datapath.source.data) self.specials += DifferentialOutput(data, pads.tx_p, pads.tx_n) class _SerdesRX(Module): - def __init__(self, pads, mode="master"): + def __init__(self, pads): # Control self.bitslip_value = bitslip_value = Signal(6) @@ -91,9 +60,7 @@ class _SerdesRX(Module): self.comma = comma = Signal() # Datapath - self.ce = ce = Signal() - self.k = k = Signal(4) - self.d = d = Signal(32) + self.source = source = stream.Endpoint([("data", 32)]) # # # @@ -103,50 +70,15 @@ class _SerdesRX(Module): self.specials += DifferentialInput(pads.rx_p, pads.rx_n, data) self.sync += data_d.eq(data) - # 1 --> 40 converter and bitslip - converter = stream.Converter(1, 40) - self.submodules += converter - bitslip = CEInserter()(BitSlip(40)) - self.submodules += bitslip + # Datapath + self.submodules.datapath = datapath = RXDatapath(1) self.comb += [ - converter.sink.stb.eq(1), - converter.source.ack.eq(1), - # Enable pipeline when converter outputs the 40 bits - ce.eq(converter.source.stb), - # Connect input data to converter - converter.sink.data.eq(data), - # Connect converter to bitslip - bitslip.ce.eq(ce), - bitslip.value.eq(bitslip_value), - bitslip.i.eq(converter.source.data) - ] - - # 8b10b decoder - self.submodules.decoders = decoders = [CEInserter()(Decoder(True)) for _ in range(4)] - self.comb += [decoders[i].ce.eq(ce) for i in range(4)] - self.comb += [ - # Connect bitslip to decoder - decoders[0].input.eq(bitslip.o[0:10]), - decoders[1].input.eq(bitslip.o[10:20]), - decoders[2].input.eq(bitslip.o[20:30]), - decoders[3].input.eq(bitslip.o[30:40]), - # Connect decoder to output - self.k.eq(Cat(*[decoders[i].k for i in range(4)])), - self.d.eq(Cat(*[decoders[i].d for i in range(4)])), - ] - - # Status - idle_timer = WaitTimer(256) - self.submodules += idle_timer - self.comb += [ - idle_timer.wait.eq(1), - self.idle.eq(idle_timer.done & - ((bitslip.o == 0) | (bitslip.o == (2**40-1)))), - self.comma.eq( - (decoders[0].k == 1) & (decoders[0].d == K(28,5)) & - (decoders[1].k == 0) & (decoders[1].d == 0) & - (decoders[2].k == 0) & (decoders[2].d == 0) & - (decoders[3].k == 0) & (decoders[3].d == 0)) + datapath.sink.stb.eq(1), + datapath.sink.data.eq(data_d), + datapath.bitslip_value.eq(bitslip_value), + datapath.source.connect(source), + idle.eq(datapath.idle), + comma.eq(datapath.comma) ] @@ -154,8 +86,8 @@ class _SerdesRX(Module): class _Serdes(Module): def __init__(self, pads, mode="master"): self.submodules.clocking = _SerdesClocking(pads, mode) - self.submodules.tx = _SerdesTX(pads, mode) - self.submodules.rx = _SerdesRX(pads, mode) + self.submodules.tx = _SerdesTX(pads) + self.submodules.rx = _SerdesRX(pads) # SERWB Master <--> Slave physical synchronization process: @@ -378,34 +310,21 @@ class SERWBPHY(Module, AutoCSR): self.submodules.init = _SerdesSlaveInit(self.serdes, init_timeout) self.submodules.control = _SerdesControl(self.serdes, self.init, mode) - # scrambling - self.submodules.scrambler = scrambler = Scrambler() - self.submodules.descrambler = descrambler = Descrambler() - - # 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 + # tx/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) + sink.connect(self.serdes.tx.sink), + self.serdes.rx.source.connect(source) + ).Else( + self.serdes.rx.source.ack.eq(1) ), - # 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)) + self.serdes.tx.sink.stb.eq(1) # always transmitting ] + + # 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.comb += self.control.prbs_error.eq( + source.stb & + source.ack & + (source.data != 0)) diff --git a/artiq/gateware/serwb/kuserdes.py b/artiq/gateware/serwb/kuserdes.py index ced959eff..f16d1919f 100644 --- a/artiq/gateware/serwb/kuserdes.py +++ b/artiq/gateware/serwb/kuserdes.py @@ -5,9 +5,7 @@ from migen.genlib.misc import BitSlip, WaitTimer from misoc.interconnect import stream from misoc.cores.code_8b10b import Encoder, Decoder - -def K(x, y): - return (y << 5) | x +from artiq.gateware.serwb.datapath import TXDatapath, RXDatapath class _KUSerdesClocking(Module): @@ -45,52 +43,27 @@ class _KUSerdesClocking(Module): class _KUSerdesTX(Module): - def __init__(self, pads, mode="master"): + def __init__(self, pads): # Control self.idle = idle = Signal() self.comma = comma = Signal() # Datapath - self.ce = ce = Signal() - self.k = k = Signal(4) - self.d = d = Signal(32) + self.sink = sink = stream.Endpoint([("data", 32)]) # # # - # 8b10b encoder - self.submodules.encoder = encoder = CEInserter()(Encoder(4, True)) - self.comb += encoder.ce.eq(ce) - # 40 --> 8 converter - converter = stream.Converter(40, 8) - self.submodules += converter + # Datapath + self.submodules.datapath = datapath = TXDatapath(8) self.comb += [ - converter.sink.stb.eq(1), - converter.source.ack.eq(1), - # Enable pipeline when converter accepts the 40 bits - ce.eq(converter.sink.ack), - # If not idle, connect encoder to converter - If(~idle, - converter.sink.data.eq(Cat(*[encoder.output[i] for i in range(4)])) - ), - # If comma, send K28.5 - If(comma, - encoder.k[0].eq(1), - encoder.d[0].eq(K(28,5)), - # Else connect TX to encoder - ).Else( - encoder.k[0].eq(k[0]), - encoder.k[1].eq(k[1]), - encoder.k[2].eq(k[2]), - encoder.k[3].eq(k[3]), - encoder.d[0].eq(d[0:8]), - encoder.d[1].eq(d[8:16]), - encoder.d[2].eq(d[16:24]), - encoder.d[3].eq(d[24:32]) - ) + sink.connect(datapath.sink), + datapath.source.ack.eq(1), + datapath.idle.eq(idle), + datapath.comma.eq(comma) ] - # Data output (DDR with sys4x) + # Output Data(DDR with sys4x) data = Signal() self.specials += [ Instance("OSERDESE3", @@ -100,14 +73,14 @@ class _KUSerdesTX(Module): o_OQ=data, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D=converter.source.data + i_D=datapath.source.data ), DifferentialOutput(data, pads.tx_p, pads.tx_n) ] class _KUSerdesRX(Module): - def __init__(self, pads, mode="master"): + def __init__(self, pads): # Control self.delay_rst = Signal() self.delay_inc = Signal() @@ -118,9 +91,7 @@ class _KUSerdesRX(Module): self.comma = comma = Signal() # Datapath - self.ce = ce = Signal() - self.k = k = Signal(4) - self.d = d = Signal(32) + self.source = source = stream.Endpoint([("data", 32)]) # # # @@ -158,50 +129,15 @@ class _KUSerdesRX(Module): ) ] - # 8 --> 40 converter and bitslip - converter = stream.Converter(8, 40) - self.submodules += converter - bitslip = CEInserter()(BitSlip(40)) - self.submodules += bitslip + # Datapath + self.submodules.datapath = datapath = RXDatapath(8) self.comb += [ - converter.sink.stb.eq(1), - converter.source.ack.eq(1), - # Enable pipeline when converter outputs the 40 bits - ce.eq(converter.source.stb), - # Connect input data to converter - converter.sink.data.eq(data_deserialized), - # Connect converter to bitslip - bitslip.ce.eq(ce), - bitslip.value.eq(bitslip_value), - bitslip.i.eq(converter.source.data) - ] - - # 8b10b decoder - self.submodules.decoders = decoders = [CEInserter()(Decoder(True)) for _ in range(4)] - self.comb += [decoders[i].ce.eq(ce) for i in range(4)] - self.comb += [ - # Connect bitslip to decoder - decoders[0].input.eq(bitslip.o[0:10]), - decoders[1].input.eq(bitslip.o[10:20]), - decoders[2].input.eq(bitslip.o[20:30]), - decoders[3].input.eq(bitslip.o[30:40]), - # Connect decoder to output - self.k.eq(Cat(*[decoders[i].k for i in range(4)])), - self.d.eq(Cat(*[decoders[i].d for i in range(4)])), - ] - - # Status - idle_timer = WaitTimer(256) - self.submodules += idle_timer - self.comb += [ - idle_timer.wait.eq(1), - self.idle.eq(idle_timer.done & - ((bitslip.o == 0) | (bitslip.o == (2**40-1)))), - self.comma.eq( - (decoders[0].k == 1) & (decoders[0].d == K(28,5)) & - (decoders[1].k == 0) & (decoders[1].d == 0) & - (decoders[2].k == 0) & (decoders[2].d == 0) & - (decoders[3].k == 0) & (decoders[3].d == 0)) + datapath.sink.stb.eq(1), + datapath.sink.data.eq(data_deserialized), + datapath.bitslip_value.eq(bitslip_value), + datapath.source.connect(source), + idle.eq(datapath.idle), + comma.eq(datapath.comma) ] @@ -209,5 +145,5 @@ class _KUSerdesRX(Module): class KUSerdes(Module): def __init__(self, pads, mode="master"): self.submodules.clocking = _KUSerdesClocking(pads, mode) - self.submodules.tx = _KUSerdesTX(pads, mode) - self.submodules.rx = _KUSerdesRX(pads, mode) + self.submodules.tx = _KUSerdesTX(pads) + self.submodules.rx = _KUSerdesRX(pads) diff --git a/artiq/gateware/serwb/phy.py b/artiq/gateware/serwb/phy.py index 83f47ed27..efb2463e2 100644 --- a/artiq/gateware/serwb/phy.py +++ b/artiq/gateware/serwb/phy.py @@ -4,14 +4,13 @@ from migen.genlib.misc import WaitTimer from misoc.interconnect import stream from misoc.interconnect.csr import * -from artiq.gateware.serwb.scrambler import Scrambler, Descrambler from artiq.gateware.serwb.kuserdes import KUSerdes from artiq.gateware.serwb.s7serdes import S7Serdes -# Master <--> Slave synchronization: -# 1) Master sends idle pattern (zeroes) to reset Slave. -# 2) Master sends K28.5 commas to allow Slave to calibrate, Slave sends idle pattern. +# SERWB Master <--> Slave physical synchronization process: +# 1) Master sends idle patterns (zeroes) to Slave to reset it. +# 2) Master sends K28.5 commas to allow Slave to calibrate, Slave sends idle patterns. # 3) Slave sends K28.5 commas to allow Master to calibrate, Master sends K28.5 commas. # 4) Master stops sending K28.5 commas. # 5) Slave stops sending K28.5 commas. @@ -360,34 +359,21 @@ class SERWBPHY(Module, AutoCSR): self.submodules.init = _SerdesSlaveInit(self.serdes, taps, init_timeout) self.submodules.control = _SerdesControl(self.serdes, self.init, mode) - # scrambling - self.submodules.scrambler = scrambler = Scrambler() - self.submodules.descrambler = descrambler = Descrambler() - - # 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 + # tx/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) + sink.connect(self.serdes.tx.sink), + self.serdes.rx.source.connect(source) + ).Else( + self.serdes.rx.source.ack.eq(1) ), - # 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)) + self.serdes.tx.sink.stb.eq(1) # always transmitting ] + + # 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.comb += self.control.prbs_error.eq( + source.stb & + source.ack & + (source.data != 0)) diff --git a/artiq/gateware/serwb/s7serdes.py b/artiq/gateware/serwb/s7serdes.py index 12fabade0..9daee338a 100644 --- a/artiq/gateware/serwb/s7serdes.py +++ b/artiq/gateware/serwb/s7serdes.py @@ -5,9 +5,7 @@ from migen.genlib.misc import BitSlip, WaitTimer from misoc.interconnect import stream from misoc.cores.code_8b10b import Encoder, Decoder - -def K(x, y): - return (y << 5) | x +from artiq.gateware.serwb.datapath import TXDatapath, RXDatapath class _S7SerdesClocking(Module): @@ -55,46 +53,20 @@ class _S7SerdesTX(Module): self.comma = comma = Signal() # Datapath - self.ce = ce = Signal() - self.k = k = Signal(4) - self.d = d = Signal(32) + self.sink = sink = stream.Endpoint([("data", 32)]) # # # - # 8b10b encoder - self.submodules.encoder = encoder = CEInserter()(Encoder(4, True)) - self.comb += encoder.ce.eq(ce) - - # 40 --> 8 converter - converter = stream.Converter(40, 8) - self.submodules += converter + # Datapath + self.submodules.datapath = datapath = TXDatapath(8) self.comb += [ - converter.sink.stb.eq(1), - converter.source.ack.eq(1), - # Enable pipeline when converter accepts the 40 bits - ce.eq(converter.sink.ack), - # If not idle, connect encoder to converter - If(~idle, - converter.sink.data.eq(Cat(*[encoder.output[i] for i in range(4)])) - ), - # If comma, send K28.5 - If(comma, - encoder.k[0].eq(1), - encoder.d[0].eq(K(28,5)), - # Else connect TX to encoder - ).Else( - encoder.k[0].eq(k[0]), - encoder.k[1].eq(k[1]), - encoder.k[2].eq(k[2]), - encoder.k[3].eq(k[3]), - encoder.d[0].eq(d[0:8]), - encoder.d[1].eq(d[8:16]), - encoder.d[2].eq(d[16:24]), - encoder.d[3].eq(d[24:32]) - ) + sink.connect(datapath.sink), + datapath.source.ack.eq(1), + datapath.idle.eq(idle), + datapath.comma.eq(comma) ] - # Data output (DDR with sys4x) + # Output Data(DDR with sys4x) data = Signal() self.specials += [ Instance("OSERDESE2", @@ -106,10 +78,10 @@ class _S7SerdesTX(Module): i_OCE=1, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D1=converter.source.data[0], i_D2=converter.source.data[1], - i_D3=converter.source.data[2], i_D4=converter.source.data[3], - i_D5=converter.source.data[4], i_D6=converter.source.data[5], - i_D7=converter.source.data[6], i_D8=converter.source.data[7] + i_D1=datapath.source.data[0], i_D2=datapath.source.data[1], + i_D3=datapath.source.data[2], i_D4=datapath.source.data[3], + i_D5=datapath.source.data[4], i_D6=datapath.source.data[5], + i_D7=datapath.source.data[6], i_D8=datapath.source.data[7] ), DifferentialOutput(data, pads.tx_p, pads.tx_n) ] @@ -127,9 +99,7 @@ class _S7SerdesRX(Module): self.comma = comma = Signal() # Datapath - self.ce = ce = Signal() - self.k = k = Signal(4) - self.d = d = Signal(32) + self.source = source = stream.Endpoint([("data", 32)]) # # # @@ -170,50 +140,15 @@ class _S7SerdesRX(Module): ) ] - # 8 --> 40 converter and bitslip - converter = stream.Converter(8, 40) - self.submodules += converter - bitslip = CEInserter()(BitSlip(40)) - self.submodules += bitslip + # Datapath + self.submodules.datapath = datapath = RXDatapath(8) self.comb += [ - converter.sink.stb.eq(1), - converter.source.ack.eq(1), - # Enable pipeline when converter outputs the 40 bits - ce.eq(converter.source.stb), - # Connect input data to converter - converter.sink.data.eq(data_deserialized), - # Connect converter to bitslip - bitslip.ce.eq(ce), - bitslip.value.eq(bitslip_value), - bitslip.i.eq(converter.source.data) - ] - - # 8b10b decoder - self.submodules.decoders = decoders = [CEInserter()(Decoder(True)) for _ in range(4)] - self.comb += [decoders[i].ce.eq(ce) for i in range(4)] - self.comb += [ - # Connect bitslip to decoder - decoders[0].input.eq(bitslip.o[0:10]), - decoders[1].input.eq(bitslip.o[10:20]), - decoders[2].input.eq(bitslip.o[20:30]), - decoders[3].input.eq(bitslip.o[30:40]), - # Connect decoder to output - self.k.eq(Cat(*[decoders[i].k for i in range(4)])), - self.d.eq(Cat(*[decoders[i].d for i in range(4)])), - ] - - # Status - idle_timer = WaitTimer(256) - self.submodules += idle_timer - self.comb += [ - idle_timer.wait.eq(1), - self.idle.eq(idle_timer.done & - ((bitslip.o == 0) | (bitslip.o == (2**40-1)))), - self.comma.eq( - (decoders[0].k == 1) & (decoders[0].d == K(28,5)) & - (decoders[1].k == 0) & (decoders[1].d == 0) & - (decoders[2].k == 0) & (decoders[2].d == 0) & - (decoders[3].k == 0) & (decoders[3].d == 0)) + datapath.sink.stb.eq(1), + datapath.sink.data.eq(data_deserialized), + datapath.bitslip_value.eq(bitslip_value), + datapath.source.connect(source), + idle.eq(datapath.idle), + comma.eq(datapath.comma) ]