diff --git a/artiq/gateware/serwb/core.py b/artiq/gateware/serwb/core.py index 4e190e03b..a49d7231c 100644 --- a/artiq/gateware/serwb/core.py +++ b/artiq/gateware/serwb/core.py @@ -17,37 +17,37 @@ class SERWBCore(Module): packetizer = Packetizer() self.submodules += depacketizer, packetizer - # 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 + # fifos + tx_fifo = stream.SyncFIFO([("data", 32)], 16) + rx_fifo = stream.SyncFIFO([("data", 32)], 16) + self.submodules += tx_fifo, rx_fifo # scrambling - scrambler = ClockDomainsRenamer(phy.cd)(Scrambler(enable=with_scrambling)) - descrambler = ClockDomainsRenamer(phy.cd)(Descrambler(enable=with_scrambling)) + scrambler = Scrambler(enable=with_scrambling) + descrambler = Descrambler(enable=with_scrambling) self.submodules += scrambler, descrambler # modules connection self.comb += [ # core --> phy - packetizer.source.connect(tx_cdc.sink), - tx_cdc.source.connect(scrambler.sink), + packetizer.source.connect(tx_fifo.sink), + tx_fifo.source.connect(scrambler.sink), If(phy.init.ready, - If(scrambler.source.stb, + If(scrambler.source.valid, phy.serdes.tx_k.eq(scrambler.source.k), phy.serdes.tx_d.eq(scrambler.source.d) ), - scrambler.source.ack.eq(1) + scrambler.source.ready.eq(phy.serdes.tx_ce) ), # phy --> core - descrambler.sink.stb.eq(phy.init.ready), - 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), + If(phy.init.ready, + descrambler.sink.valid.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), # etherbone <--> core depacketizer.source.connect(etherbone.sink), diff --git a/artiq/gateware/serwb/kusphy.py b/artiq/gateware/serwb/kusphy.py index e0b9baa1f..cfd10d94b 100644 --- a/artiq/gateware/serwb/kusphy.py +++ b/artiq/gateware/serwb/kusphy.py @@ -1,18 +1,26 @@ from migen import * -from migen.genlib.resetsync import AsyncResetSynchronizer -from migen.genlib.cdc import MultiReg, PulseSynchronizer, Gearbox from migen.genlib.misc import BitSlip +from migen.genlib.misc import WaitTimer +from misoc.interconnect import stream from misoc.cores.code_8b10b import Encoder, Decoder +def K(x, y): + return (y << 5) | x + + +@ResetInserter() class KUSSerdes(Module): def __init__(self, pads, mode="master"): if mode == "slave": self.refclk = Signal() + self.tx_ce = Signal() self.tx_k = Signal(4) self.tx_d = Signal(32) + + self.rx_ce = Signal() self.rx_k = Signal(4) self.rx_d = Signal(32) @@ -24,16 +32,14 @@ class KUSSerdes(Module): self.rx_bitslip_value = Signal(6) self.rx_delay_rst = Signal() self.rx_delay_inc = Signal() - self.rx_delay_ce = Signal() self.rx_delay_en_vtc = Signal() # # # - self.submodules.encoder = ClockDomainsRenamer("sys0p2x")( - Encoder(4, True)) - self.decoders = [ClockDomainsRenamer("sys0p2x")( - Decoder(True)) for _ in range(4)] - self.submodules += self.decoders + self.submodules.encoder = encoder = CEInserter()(Encoder(4, True)) + self.comb += encoder.ce.eq(self.tx_ce) + self.submodules.decoders = decoders = [CEInserter()(Decoder(True)) for _ in range(4)] + self.comb += [decoders[i].ce.eq(self.rx_ce) for i in range(4)] # clocking: @@ -42,53 +48,26 @@ class KUSSerdes(Module): # In Slave mode: # - linerate/10 refclk provided by clk_pads - # control/status cdc - tx_idle = Signal() - tx_comma = Signal() - rx_idle = Signal() - rx_comma = Signal() - rx_bitslip_value = Signal(6) - rx_delay_rst = Signal() - rx_delay_inc = Signal() - rx_delay_en_vtc = Signal() - rx_delay_ce = Signal() - self.specials += [ - MultiReg(self.tx_idle, tx_idle, "sys0p2x"), - MultiReg(self.tx_comma, tx_comma, "sys0p2x"), - MultiReg(rx_idle, self.rx_idle, "sys"), - MultiReg(rx_comma, self.rx_comma, "sys"), - MultiReg(self.rx_bitslip_value, rx_bitslip_value, "sys0p2x"), - MultiReg(self.rx_delay_inc, rx_delay_inc, "sys"), - MultiReg(self.rx_delay_en_vtc, rx_delay_en_vtc, "sys") - ] - self.submodules.do_rx_delay_rst = PulseSynchronizer("sys", "sys") - self.comb += [ - rx_delay_rst.eq(self.do_rx_delay_rst.o), - self.do_rx_delay_rst.i.eq(self.rx_delay_rst) - ] - self.submodules.do_rx_delay_ce = PulseSynchronizer("sys", "sys") - self.comb += [ - rx_delay_ce.eq(self.do_rx_delay_ce.o), - self.do_rx_delay_ce.i.eq(self.rx_delay_ce) - ] - # tx clock (linerate/10) if mode == "master": - self.submodules.tx_clk_gearbox = Gearbox(40, "sys0p2x", 8, "sys") - self.comb += self.tx_clk_gearbox.i.eq((0b1111100000 << 30) | - (0b1111100000 << 20) | - (0b1111100000 << 10) | - (0b1111100000 << 0)) + clk_converter = stream.Converter(40, 8) + self.submodules += clk_converter + self.comb += [ + clk_converter.sink.valid.eq(1), + clk_converter.sink.data.eq(Replicate(Signal(10, reset=0b1111100000), 4)), + clk_converter.source.ready.eq(1) + ] clk_o = Signal() self.specials += [ Instance("OSERDESE3", p_DATA_WIDTH=8, p_INIT=0, - p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, p_IS_RST_INVERTED=0, + p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, + p_IS_RST_INVERTED=0, o_OQ=clk_o, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D=self.tx_clk_gearbox.o + i_D=clk_converter.source.data ), Instance("OBUFDS", i_I=clk_o, @@ -98,29 +77,32 @@ class KUSSerdes(Module): ] # tx datapath - # tx_data -> encoders -> gearbox -> serdes - self.submodules.tx_gearbox = Gearbox(40, "sys0p2x", 8, "sys") + # tx_data -> encoders -> converter -> serdes + self.submodules.tx_converter = tx_converter = stream.Converter(40, 8) self.comb += [ - If(tx_comma, - self.encoder.k[0].eq(1), - self.encoder.d[0].eq(0xbc) + tx_converter.sink.valid.eq(1), + self.tx_ce.eq(tx_converter.sink.ready), + tx_converter.source.ready.eq(1), + If(self.tx_idle, + tx_converter.sink.data.eq(0) ).Else( - self.encoder.k[0].eq(self.tx_k[0]), - self.encoder.k[1].eq(self.tx_k[1]), - self.encoder.k[2].eq(self.tx_k[2]), - 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]) + tx_converter.sink.data.eq( + Cat(*[encoder.output[i] for i in range(4)])) + ), + If(self.tx_comma, + encoder.k[0].eq(1), + encoder.d[0].eq(K(28,5)), + ).Else( + encoder.k[0].eq(self.tx_k[0]), + encoder.k[1].eq(self.tx_k[1]), + encoder.k[2].eq(self.tx_k[2]), + encoder.k[3].eq(self.tx_k[3]), + encoder.d[0].eq(self.tx_d[0:8]), + encoder.d[1].eq(self.tx_d[8:16]), + encoder.d[2].eq(self.tx_d[16:24]), + encoder.d[3].eq(self.tx_d[24:32]) ) ] - self.sync.sys0p2x += \ - If(tx_idle, - self.tx_gearbox.i.eq(0) - ).Else( - self.tx_gearbox.i.eq(Cat(*[self.encoder.output[i] for i in range(4)])) - ) serdes_o = Signal() self.specials += [ @@ -131,7 +113,7 @@ class KUSSerdes(Module): o_OQ=serdes_o, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D=self.tx_gearbox.o + i_D=tx_converter.source.data ), Instance("OBUFDS", i_I=serdes_o, @@ -163,9 +145,14 @@ class KUSSerdes(Module): self.comb += self.refclk.eq(clk_i_bufg) # rx datapath - # serdes -> gearbox -> bitslip -> decoders -> rx_data - self.submodules.rx_gearbox = Gearbox(8, "sys", 40, "sys0p2x") - self.submodules.rx_bitslip = ClockDomainsRenamer("sys0p2x")(BitSlip(40)) + # serdes -> converter -> bitslip -> decoders -> rx_data + self.submodules.rx_converter = rx_converter = stream.Converter(8, 40) + self.comb += [ + self.rx_ce.eq(rx_converter.source.valid), + rx_converter.source.ready.eq(1) + ] + self.submodules.rx_bitslip = rx_bitslip = CEInserter()(BitSlip(40)) + self.comb += rx_bitslip.ce.eq(self.rx_ce) serdes_i_nodelay = Signal() self.specials += [ @@ -186,9 +173,9 @@ class KUSSerdes(Module): p_DELAY_TYPE="VARIABLE", p_DELAY_VALUE=0, i_CLK=ClockSignal("sys"), - i_RST=rx_delay_rst, i_LOAD=0, - i_INC=rx_delay_inc, i_EN_VTC=rx_delay_en_vtc, - i_CE=rx_delay_ce, + i_RST=self.rx_delay_rst, i_LOAD=0, + i_INC=1, i_EN_VTC=self.rx_delay_en_vtc, + i_CE=self.rx_delay_inc, i_IDATAIN=serdes_i_nodelay, o_DATAOUT=serdes_i_delayed ), @@ -208,19 +195,20 @@ class KUSSerdes(Module): ] self.comb += [ - self.rx_gearbox.i.eq(serdes_q), - self.rx_bitslip.value.eq(rx_bitslip_value), - self.rx_bitslip.i.eq(self.rx_gearbox.o), - self.decoders[0].input.eq(self.rx_bitslip.o[0:10]), - self.decoders[1].input.eq(self.rx_bitslip.o[10:20]), - self.decoders[2].input.eq(self.rx_bitslip.o[20:30]), - self.decoders[3].input.eq(self.rx_bitslip.o[30:40]), - 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_comma.eq(((self.decoders[0].d == 0xbc) & (self.decoders[0].k == 1)) & - ((self.decoders[1].d == 0x00) & (self.decoders[1].k == 0)) & - ((self.decoders[2].d == 0x00) & (self.decoders[2].k == 0)) & - ((self.decoders[3].d == 0x00) & (self.decoders[3].k == 0))) + rx_converter.sink.valid.eq(1), + rx_converter.sink.data.eq(serdes_q), + rx_bitslip.value.eq(self.rx_bitslip_value), + rx_bitslip.i.eq(rx_converter.source.data), + decoders[0].input.eq(rx_bitslip.o[0:10]), + decoders[1].input.eq(rx_bitslip.o[10:20]), + decoders[2].input.eq(rx_bitslip.o[20:30]), + decoders[3].input.eq(rx_bitslip.o[30:40]), + self.rx_k.eq(Cat(*[decoders[i].k for i in range(4)])), + self.rx_d.eq(Cat(*[decoders[i].d for i in range(4)])), + self.rx_comma.eq((decoders[0].k == 1) & (decoders[0].d == K(28,5))) + ] - ] + idle_timer = WaitTimer(32) + self.submodules += idle_timer + self.comb += idle_timer.wait.eq(1) + self.sync += self.rx_idle.eq(idle_timer.done & (rx_bitslip.o == 0)) diff --git a/artiq/gateware/serwb/phy.py b/artiq/gateware/serwb/phy.py index e22e436fe..46083f0fa 100644 --- a/artiq/gateware/serwb/phy.py +++ b/artiq/gateware/serwb/phy.py @@ -14,11 +14,12 @@ from artiq.gateware.serwb.s7phy import S7Serdes # 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. -# 6) Link is ready. +# 6) Physical link is ready. + +@ResetInserter() class _SerdesMasterInit(Module): - def __init__(self, serdes, taps, timeout=4096): - self.reset = Signal() + def __init__(self, serdes, taps, timeout=2**14): self.ready = Signal() self.error = Signal() @@ -31,14 +32,9 @@ class _SerdesMasterInit(Module): self.delay_max_found = delay_max_found = Signal() self.bitslip = bitslip = Signal(max=40) - timer = WaitTimer(timeout) - self.submodules += timer - - self.submodules.fsm = fsm = ResetInserter()(FSM(reset_state="IDLE")) - self.comb += self.fsm.reset.eq(self.reset) - - self.comb += serdes.rx_delay_inc.eq(1) + self.submodules.timer = timer = WaitTimer(timeout) + self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", NextValue(delay, 0), NextValue(delay_min, 0), @@ -109,14 +105,12 @@ class _SerdesMasterInit(Module): serdes.rx_delay_rst.eq(1) ).Else( NextValue(delay, delay + 1), - serdes.rx_delay_ce.eq(1) + serdes.rx_delay_inc.eq(1) ), serdes.tx_comma.eq(1) ) fsm.act("CHECK_SAMPLING_WINDOW", - If((delay_min == 0) | - (delay_max == (taps - 1)) | - ((delay_max - delay_min) < taps//16), + If((delay_max - delay_min) < taps//16, NextValue(delay_min_found, 0), NextValue(delay_max_found, 0), NextState("WAIT_STABLE") @@ -131,7 +125,6 @@ class _SerdesMasterInit(Module): ).Else( NextValue(delay, delay + 1), serdes.rx_delay_inc.eq(1), - serdes.rx_delay_ce.eq(1), NextState("WAIT_SAMPLING_WINDOW") ), serdes.tx_comma.eq(1) @@ -147,13 +140,16 @@ class _SerdesMasterInit(Module): fsm.act("READY", self.ready.eq(1) ) + if hasattr(serdes, "rx_delay_en_vtc"): + self.comb += serdes.rx_delay_en_vtc.eq(self.ready) fsm.act("ERROR", self.error.eq(1) ) +@ResetInserter() class _SerdesSlaveInit(Module, AutoCSR): - def __init__(self, serdes, taps, timeout=4096): + def __init__(self, serdes, taps, timeout=2**14): self.ready = Signal() self.error = Signal() @@ -166,13 +162,10 @@ class _SerdesSlaveInit(Module, AutoCSR): self.delay_max_found = delay_max_found = Signal() self.bitslip = bitslip = Signal(max=40) - timer = WaitTimer(timeout) - self.submodules += timer + self.submodules.timer = timer = WaitTimer(timeout) - self.comb += serdes.rx_delay_inc.eq(1) - - self.submodules.fsm = fsm = ResetInserter()(FSM(reset_state="IDLE")) - self.comb += fsm.reset.eq(serdes.rx_idle) + self.submodules.fsm = fsm = FSM(reset_state="IDLE") + # reset fsm.act("IDLE", NextValue(delay, 0), NextValue(delay_min, 0), @@ -181,7 +174,11 @@ class _SerdesSlaveInit(Module, AutoCSR): NextValue(delay_max_found, 0), serdes.rx_delay_rst.eq(1), NextValue(bitslip, 0), - NextState("WAIT_STABLE"), + timer.wait.eq(1), + If(timer.done, + timer.wait.eq(0), + NextState("WAIT_STABLE"), + ), serdes.tx_idle.eq(1) ) fsm.act("WAIT_STABLE", @@ -229,14 +226,12 @@ class _SerdesSlaveInit(Module, AutoCSR): serdes.rx_delay_rst.eq(1) ).Else( NextValue(delay, delay + 1), - serdes.rx_delay_ce.eq(1) + serdes.rx_delay_inc.eq(1) ), serdes.tx_idle.eq(1) ) fsm.act("CHECK_SAMPLING_WINDOW", - If((delay_min == 0) | - (delay_max == (taps - 1)) | - ((delay_max - delay_min) < taps//16), + If((delay_max - delay_min) < taps//16, NextValue(delay_min_found, 0), NextValue(delay_max_found, 0), NextState("WAIT_STABLE") @@ -251,7 +246,6 @@ class _SerdesSlaveInit(Module, AutoCSR): ).Else( NextValue(delay, delay + 1), serdes.rx_delay_inc.eq(1), - serdes.rx_delay_ce.eq(1), NextState("WAIT_SAMPLING_WINDOW") ) ) @@ -274,13 +268,15 @@ class _SerdesSlaveInit(Module, AutoCSR): fsm.act("READY", self.ready.eq(1) ) + if hasattr(serdes, "rx_delay_en_vtc"): + self.comb += serdes.rx_delay_en_vtc.eq(self.ready) fsm.act("ERROR", self.error.eq(1) ) class _SerdesControl(Module, AutoCSR): - def __init__(self, init, mode="master"): + def __init__(self, serdes, init, mode="master"): if mode == "master": self.reset = CSR() self.ready = CSRStatus() @@ -296,7 +292,18 @@ class _SerdesControl(Module, AutoCSR): # # # if mode == "master": + # In Master mode, reset is coming from CSR, + # it resets the Master that will also reset + # the Slave by putting the link in idle. self.comb += init.reset.eq(self.reset.re) + else: + # In Slave mode, reset is coming from link, + # Master reset the Slave by putting the link + # in idle. + self.comb += [ + init.reset.eq(serdes.rx_idle), + serdes.reset.eq(serdes.rx_idle) + ] self.comb += [ self.ready.status.eq(init.ready), self.error.status.eq(init.error), @@ -310,7 +317,6 @@ class _SerdesControl(Module, AutoCSR): class SERWBPHY(Module, AutoCSR): - cd = "sys0p2x" def __init__(self, device, pads, mode="master"): assert mode in ["master", "slave"] if device[:4] == "xcku": @@ -325,4 +331,4 @@ class SERWBPHY(Module, AutoCSR): self.submodules.init = _SerdesMasterInit(self.serdes, taps) else: self.submodules.init = _SerdesSlaveInit(self.serdes, taps) - self.submodules.control = _SerdesControl(self.init, mode) + self.submodules.control = _SerdesControl(self.serdes, self.init, mode) diff --git a/artiq/gateware/serwb/s7phy.py b/artiq/gateware/serwb/s7phy.py index a345d6823..fcd77da48 100644 --- a/artiq/gateware/serwb/s7phy.py +++ b/artiq/gateware/serwb/s7phy.py @@ -1,18 +1,26 @@ from migen import * -from migen.genlib.resetsync import AsyncResetSynchronizer -from migen.genlib.cdc import MultiReg, Gearbox from migen.genlib.misc import BitSlip +from migen.genlib.misc import WaitTimer +from misoc.interconnect import stream from misoc.cores.code_8b10b import Encoder, Decoder +def K(x, y): + return (y << 5) | x + + +@ResetInserter() class S7Serdes(Module): def __init__(self, pads, mode="master"): if mode == "slave": self.refclk = Signal() + self.tx_ce = Signal() self.tx_k = Signal(4) self.tx_d = Signal(32) + + self.rx_ce = Signal() self.rx_k = Signal(4) self.rx_d = Signal(32) @@ -24,44 +32,30 @@ class S7Serdes(Module): self.rx_bitslip_value = Signal(6) self.rx_delay_rst = Signal() self.rx_delay_inc = Signal() - self.rx_delay_ce = Signal() # # # - self.submodules.encoder = ClockDomainsRenamer("sys0p2x")( - Encoder(4, True)) - self.decoders = [ClockDomainsRenamer("sys0p2x")( - Decoder(True)) for _ in range(4)] - self.submodules += self.decoders + self.submodules.encoder = encoder = CEInserter()(Encoder(4, True)) + self.comb += encoder.ce.eq(self.tx_ce) + self.submodules.decoders = decoders = [CEInserter()(Decoder(True)) for _ in range(4)] + self.comb += [decoders[i].ce.eq(self.rx_ce) for i in range(4)] # clocking: - # In master mode: - # - linerate/10 slave refclk generated on clk_pads + # In Master mode: + # - linerate/10 refclk is generated on clk_pads # In Slave mode: - # - linerate/10 refclk provided by clk_pads - - # control/status cdc - tx_idle = Signal() - tx_comma = Signal() - rx_idle = Signal() - rx_comma = Signal() - rx_bitslip_value = Signal(6) - self.specials += [ - MultiReg(self.tx_idle, tx_idle, "sys0p2x"), - MultiReg(self.tx_comma, tx_comma, "sys0p2x"), - MultiReg(rx_idle, self.rx_idle, "sys"), - MultiReg(rx_comma, self.rx_comma, "sys") - ] - self.specials += MultiReg(self.rx_bitslip_value, rx_bitslip_value, "sys0p2x"), + # - linerate/10 refclk is provided by clk_pads # tx clock (linerate/10) if mode == "master": - self.submodules.tx_clk_gearbox = Gearbox(40, "sys0p2x", 8, "sys") - self.comb += self.tx_clk_gearbox.i.eq((0b1111100000 << 30) | - (0b1111100000 << 20) | - (0b1111100000 << 10) | - (0b1111100000 << 0)) + clk_converter = stream.Converter(40, 8) + self.submodules += clk_converter + self.comb += [ + clk_converter.sink.valid.eq(1), + clk_converter.sink.data.eq(Replicate(Signal(10, reset=0b1111100000), 4)), + clk_converter.source.ready.eq(1) + ] clk_o = Signal() self.specials += [ Instance("OSERDESE2", @@ -73,10 +67,10 @@ class S7Serdes(Module): i_OCE=1, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D1=self.tx_clk_gearbox.o[0], i_D2=self.tx_clk_gearbox.o[1], - i_D3=self.tx_clk_gearbox.o[2], i_D4=self.tx_clk_gearbox.o[3], - i_D5=self.tx_clk_gearbox.o[4], i_D6=self.tx_clk_gearbox.o[5], - i_D7=self.tx_clk_gearbox.o[6], i_D8=self.tx_clk_gearbox.o[7] + i_D1=clk_converter.source.data[0], i_D2=clk_converter.source.data[1], + i_D3=clk_converter.source.data[2], i_D4=clk_converter.source.data[3], + i_D5=clk_converter.source.data[4], i_D6=clk_converter.source.data[5], + i_D7=clk_converter.source.data[6], i_D8=clk_converter.source.data[7] ), Instance("OBUFDS", i_I=clk_o, @@ -86,29 +80,32 @@ class S7Serdes(Module): ] # tx datapath - # tx_data -> encoders -> gearbox -> serdes - self.submodules.tx_gearbox = Gearbox(40, "sys0p2x", 8, "sys") + # tx_data -> encoders -> converter -> serdes + self.submodules.tx_converter = tx_converter = stream.Converter(40, 8) self.comb += [ - If(tx_comma, - self.encoder.k[0].eq(1), - self.encoder.d[0].eq(0xbc) + tx_converter.sink.valid.eq(1), + self.tx_ce.eq(tx_converter.sink.ready), + tx_converter.source.ready.eq(1), + If(self.tx_idle, + tx_converter.sink.data.eq(0) ).Else( - self.encoder.k[0].eq(self.tx_k[0]), - self.encoder.k[1].eq(self.tx_k[1]), - self.encoder.k[2].eq(self.tx_k[2]), - 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]) + tx_converter.sink.data.eq( + Cat(*[encoder.output[i] for i in range(4)])) + ), + If(self.tx_comma, + encoder.k[0].eq(1), + encoder.d[0].eq(K(28,5)), + ).Else( + encoder.k[0].eq(self.tx_k[0]), + encoder.k[1].eq(self.tx_k[1]), + encoder.k[2].eq(self.tx_k[2]), + encoder.k[3].eq(self.tx_k[3]), + encoder.d[0].eq(self.tx_d[0:8]), + encoder.d[1].eq(self.tx_d[8:16]), + encoder.d[2].eq(self.tx_d[16:24]), + encoder.d[3].eq(self.tx_d[24:32]) ) ] - self.sync.sys0p2x += \ - If(tx_idle, - self.tx_gearbox.i.eq(0) - ).Else( - self.tx_gearbox.i.eq(Cat(*[self.encoder.output[i] for i in range(4)])) - ) serdes_o = Signal() self.specials += [ @@ -121,10 +118,10 @@ class S7Serdes(Module): i_OCE=1, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D1=self.tx_gearbox.o[0], i_D2=self.tx_gearbox.o[1], - i_D3=self.tx_gearbox.o[2], i_D4=self.tx_gearbox.o[3], - i_D5=self.tx_gearbox.o[4], i_D6=self.tx_gearbox.o[5], - i_D7=self.tx_gearbox.o[6], i_D8=self.tx_gearbox.o[7] + i_D1=tx_converter.source.data[0], i_D2=tx_converter.source.data[1], + i_D3=tx_converter.source.data[2], i_D4=tx_converter.source.data[3], + i_D5=tx_converter.source.data[4], i_D6=tx_converter.source.data[5], + i_D7=tx_converter.source.data[6], i_D8=tx_converter.source.data[7] ), Instance("OBUFDS", i_I=serdes_o, @@ -156,9 +153,14 @@ class S7Serdes(Module): self.comb += self.refclk.eq(clk_i_bufg) # rx datapath - # serdes -> gearbox -> bitslip -> decoders -> rx_data - self.submodules.rx_gearbox = Gearbox(8, "sys", 40, "sys0p2x") - self.submodules.rx_bitslip = ClockDomainsRenamer("sys0p2x")(BitSlip(40)) + # serdes -> converter -> bitslip -> decoders -> rx_data + self.submodules.rx_converter = rx_converter = stream.Converter(8, 40) + self.comb += [ + self.rx_ce.eq(rx_converter.source.valid), + rx_converter.source.ready.eq(1) + ] + self.submodules.rx_bitslip = rx_bitslip = CEInserter()(BitSlip(40)) + self.comb += rx_bitslip.ce.eq(self.rx_ce) serdes_i_nodelay = Signal() self.specials += [ @@ -180,8 +182,8 @@ class S7Serdes(Module): i_C=ClockSignal(), i_LD=self.rx_delay_rst, - i_CE=self.rx_delay_ce, - i_LDPIPEEN=0, i_INC=self.rx_delay_inc, + i_CE=self.rx_delay_inc, + i_LDPIPEEN=0, i_INC=1, i_IDATAIN=serdes_i_nodelay, o_DATAOUT=serdes_i_delayed ), @@ -204,19 +206,20 @@ class S7Serdes(Module): ] self.comb += [ - self.rx_gearbox.i.eq(serdes_q), - self.rx_bitslip.value.eq(rx_bitslip_value), - self.rx_bitslip.i.eq(self.rx_gearbox.o), - self.decoders[0].input.eq(self.rx_bitslip.o[0:10]), - self.decoders[1].input.eq(self.rx_bitslip.o[10:20]), - self.decoders[2].input.eq(self.rx_bitslip.o[20:30]), - self.decoders[3].input.eq(self.rx_bitslip.o[30:40]), - 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_comma.eq(((self.decoders[0].d == 0xbc) & (self.decoders[0].k == 1)) & - ((self.decoders[1].d == 0x00) & (self.decoders[1].k == 0)) & - ((self.decoders[2].d == 0x00) & (self.decoders[2].k == 0)) & - ((self.decoders[3].d == 0x00) & (self.decoders[3].k == 0))) + rx_converter.sink.valid.eq(1), + rx_converter.sink.data.eq(serdes_q), + rx_bitslip.value.eq(self.rx_bitslip_value), + rx_bitslip.i.eq(rx_converter.source.data), + decoders[0].input.eq(rx_bitslip.o[0:10]), + decoders[1].input.eq(rx_bitslip.o[10:20]), + decoders[2].input.eq(rx_bitslip.o[20:30]), + decoders[3].input.eq(rx_bitslip.o[30:40]), + self.rx_k.eq(Cat(*[decoders[i].k for i in range(4)])), + self.rx_d.eq(Cat(*[decoders[i].d for i in range(4)])), + self.rx_comma.eq((decoders[0].k == 1) & (decoders[0].d == K(28,5))) + ] - ] + idle_timer = WaitTimer(32) + self.submodules += idle_timer + self.comb += idle_timer.wait.eq(1) + self.sync += self.rx_idle.eq(idle_timer.done & (rx_bitslip.o == 0)) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 6ff2f73ed..0dd27d30a 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -174,7 +174,7 @@ class Standalone(MiniSoC, AMPSoC): self.submodules.serwb_phy_amc = serwb_phy_amc self.csr_devices.append("serwb_phy_amc") - serwb_core = serwb.core.SERWBCore(serwb_phy_amc, int(self.clk_freq), mode="slave", with_scrambling=True) + serwb_core = serwb.core.SERWBCore(serwb_phy_amc, int(self.clk_freq), mode="slave", with_scrambling=False) self.submodules += serwb_core self.add_wb_slave(self.mem_map["serwb"], 8192, serwb_core.etherbone.wishbone.bus) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 08ed4245c..49b95a92c 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -168,7 +168,7 @@ class SaymaRTM(Module): self.comb += self.crg.serwb_refclk.eq(serwb_phy_rtm.serdes.refclk) csr_devices.append("serwb_phy_rtm") - serwb_core = serwb.core.SERWBCore(serwb_phy_rtm, int(clk_freq), mode="master", with_scrambling=True) + serwb_core = serwb.core.SERWBCore(serwb_phy_rtm, int(clk_freq), mode="master", with_scrambling=False) self.submodules += serwb_core # process CSR devices and connect them to serwb