From 41d57d64f6acdaa8c6034b2fe397886be54199fa Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 30 Aug 2017 14:31:44 +0200 Subject: [PATCH] gateware/serwb: SERWBPLL, SERWBPHY, SERWBCore and add checks in delay finding to verify the sampling window --- artiq/gateware/serwb/__init__.py | 2 +- artiq/gateware/serwb/core.py | 37 +++++++++ artiq/gateware/serwb/etherbone.py | 60 +++++++------- artiq/gateware/serwb/kusphy.py | 57 ------------- artiq/gateware/serwb/phy.py | 130 ++++++++++++++++++++++++++---- artiq/gateware/serwb/s7phy.py | 57 ------------- 6 files changed, 182 insertions(+), 161 deletions(-) create mode 100644 artiq/gateware/serwb/core.py diff --git a/artiq/gateware/serwb/__init__.py b/artiq/gateware/serwb/__init__.py index 632008428..3ebf3f028 100644 --- a/artiq/gateware/serwb/__init__.py +++ b/artiq/gateware/serwb/__init__.py @@ -1 +1 @@ -from artiq.gateware.serwb import s7phy, kusphy, phy, packet, etherbone +from artiq.gateware.serwb import s7phy, kusphy, phy, core, packet, etherbone diff --git a/artiq/gateware/serwb/core.py b/artiq/gateware/serwb/core.py new file mode 100644 index 000000000..d96f77dc6 --- /dev/null +++ b/artiq/gateware/serwb/core.py @@ -0,0 +1,37 @@ +from migen import * + +from misoc.interconnect import stream + +from artiq.gateware.serwb.packet import Depacketizer, Packetizer +from artiq.gateware.serwb.etherbone import Etherbone + + +class SERWBCore(Module): + def __init__(self, phy, clk_freq, mode): + self.submodules.etherbone = etherbone = Etherbone(mode) + depacketizer = Depacketizer(clk_freq) + packetizer = Packetizer() + self.submodules += depacketizer, packetizer + tx_cdc = stream.AsyncFIFO([("data", 32)], 8) + tx_cdc = ClockDomainsRenamer({"write": "sys", "read": "serdes"})(tx_cdc) + self.submodules += tx_cdc + rx_cdc = stream.AsyncFIFO([("data", 32)], 8) + rx_cdc = ClockDomainsRenamer({"write": "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 + packetizer.source.connect(tx_cdc.sink), + If(tx_cdc.source.stb & phy.init.ready, + phy.serdes.tx_data.eq(tx_cdc.source.data) + ), + tx_cdc.source.ack.eq(phy.init.ready), + + # serdes --> core + rx_cdc.sink.stb.eq(phy.init.ready), + rx_cdc.sink.data.eq(phy.serdes.rx_data), + rx_cdc.source.connect(depacketizer.sink), + ] diff --git a/artiq/gateware/serwb/etherbone.py b/artiq/gateware/serwb/etherbone.py index 9ac7bdb7e..231299bed 100644 --- a/artiq/gateware/serwb/etherbone.py +++ b/artiq/gateware/serwb/etherbone.py @@ -18,7 +18,7 @@ from misoc.interconnect import wishbone from artiq.gateware.serwb.packet import * -class Packetizer(Module): +class _Packetizer(Module): def __init__(self, sink_description, source_description, header): self.sink = sink = stream.Endpoint(sink_description) self.source = source = stream.Endpoint(source_description) @@ -108,7 +108,7 @@ class Packetizer(Module): ) -class Depacketizer(Module): +class _Depacketizer(Module): def __init__(self, sink_description, source_description, header): self.sink = sink = stream.Endpoint(sink_description) self.source = source = stream.Endpoint(source_description) @@ -275,22 +275,22 @@ def etherbone_mmap_description(dw): # etherbone packet -class EtherbonePacketPacketizer(Packetizer): +class _EtherbonePacketPacketizer(_Packetizer): def __init__(self): - Packetizer.__init__(self, + _Packetizer.__init__(self, etherbone_packet_description(32), user_description(32), etherbone_packet_header) -class EtherbonePacketTX(Module): +class _EtherbonePacketTX(Module): def __init__(self): self.sink = sink = stream.Endpoint(etherbone_packet_user_description(32)) self.source = source = stream.Endpoint(user_description(32)) # # # - self.submodules.packetizer = packetizer = EtherbonePacketPacketizer() + self.submodules.packetizer = packetizer = _EtherbonePacketPacketizer() self.comb += [ packetizer.sink.stb.eq(sink.stb), packetizer.sink.eop.eq(sink.eop), @@ -321,22 +321,22 @@ class EtherbonePacketTX(Module): ) -class EtherbonePacketDepacketizer(Depacketizer): +class _EtherbonePacketDepacketizer(_Depacketizer): def __init__(self): - Depacketizer.__init__(self, + _Depacketizer.__init__(self, user_description(32), etherbone_packet_description(32), etherbone_packet_header) -class EtherbonePacketRX(Module): +class _EtherbonePacketRX(Module): def __init__(self): self.sink = sink = stream.Endpoint(user_description(32)) self.source = source = stream.Endpoint(etherbone_packet_user_description(32)) # # # - self.submodules.depacketizer = depacketizer = EtherbonePacketDepacketizer() + self.submodules.depacketizer = depacketizer = _EtherbonePacketDepacketizer() self.comb += sink.connect(depacketizer.sink) self.submodules.fsm = fsm = FSM(reset_state="IDLE") @@ -385,10 +385,10 @@ class EtherbonePacketRX(Module): ) -class EtherbonePacket(Module): +class _EtherbonePacket(Module): def __init__(self, port_sink, port_source): - self.submodules.tx = tx = EtherbonePacketTX() - self.submodules.rx = rx = EtherbonePacketRX() + self.submodules.tx = tx = _EtherbonePacketTX() + self.submodules.rx = rx = _EtherbonePacketRX() self.comb += [ tx.source.connect(port_sink), port_source.connect(rx.sink) @@ -397,23 +397,23 @@ class EtherbonePacket(Module): # etherbone record -class EtherboneRecordPacketizer(Packetizer): +class _EtherboneRecordPacketizer(_Packetizer): def __init__(self): - Packetizer.__init__(self, + _Packetizer.__init__(self, etherbone_record_description(32), etherbone_packet_user_description(32), etherbone_record_header) -class EtherboneRecordDepacketizer(Depacketizer): +class _EtherboneRecordDepacketizer(_Depacketizer): def __init__(self): - Depacketizer.__init__(self, + _Depacketizer.__init__(self, etherbone_packet_user_description(32), etherbone_record_description(32), etherbone_record_header) -class EtherboneRecordReceiver(Module): +class _EtherboneRecordReceiver(Module): def __init__(self, buffer_depth=256): self.sink = sink = stream.Endpoint(etherbone_record_description(32)) self.source = source = stream.Endpoint(etherbone_mmap_description(32)) @@ -496,7 +496,7 @@ class EtherboneRecordReceiver(Module): ) -class EtherboneRecordSender(Module): +class _EtherboneRecordSender(Module): def __init__(self, buffer_depth=256): self.sink = sink = stream.Endpoint(etherbone_mmap_description(32)) self.source = source = stream.Endpoint(etherbone_record_description(32)) @@ -545,7 +545,7 @@ class EtherboneRecordSender(Module): ) -class EtherboneRecord(Module): +class _EtherboneRecord(Module): def __init__(self): self.sink = sink = stream.Endpoint(etherbone_packet_user_description(32)) self.source = source = stream.Endpoint(etherbone_packet_user_description(32)) @@ -553,16 +553,16 @@ class EtherboneRecord(Module): # # # # receive record, decode it and generate mmap stream - self.submodules.depacketizer = depacketizer = EtherboneRecordDepacketizer() - self.submodules.receiver = receiver = EtherboneRecordReceiver() + self.submodules.depacketizer = depacketizer = _EtherboneRecordDepacketizer() + self.submodules.receiver = receiver = _EtherboneRecordReceiver() self.comb += [ sink.connect(depacketizer.sink), depacketizer.source.connect(receiver.sink) ] # receive mmap stream, encode it and send records - self.submodules.sender = sender = EtherboneRecordSender() - self.submodules.packetizer = packetizer = EtherboneRecordPacketizer() + self.submodules.sender = sender = _EtherboneRecordSender() + self.submodules.packetizer = packetizer = _EtherboneRecordPacketizer() self.comb += [ sender.source.connect(packetizer.sink), packetizer.source.connect(source), @@ -574,7 +574,7 @@ class EtherboneRecord(Module): # etherbone wishbone -class EtherboneWishboneMaster(Module): +class _EtherboneWishboneMaster(Module): def __init__(self): self.sink = sink = stream.Endpoint(etherbone_mmap_description(32)) self.source = source = stream.Endpoint(etherbone_mmap_description(32)) @@ -642,7 +642,7 @@ class EtherboneWishboneMaster(Module): ) -class EtherboneWishboneSlave(Module): +class _EtherboneWishboneSlave(Module): def __init__(self): self.bus = bus = wishbone.Interface() self.ready = Signal(reset=1) @@ -723,12 +723,12 @@ class Etherbone(Module): # # # - self.submodules.packet = EtherbonePacket(source, sink) - self.submodules.record = EtherboneRecord() + self.submodules.packet = _EtherbonePacket(source, sink) + self.submodules.record = _EtherboneRecord() if mode == "master": - self.submodules.wishbone = EtherboneWishboneMaster() + self.submodules.wishbone = _EtherboneWishboneMaster() elif mode == "slave": - self.submodules.wishbone = EtherboneWishboneSlave() + self.submodules.wishbone = _EtherboneWishboneSlave() else: raise ValueError diff --git a/artiq/gateware/serwb/kusphy.py b/artiq/gateware/serwb/kusphy.py index 412f469e4..49e423ff8 100644 --- a/artiq/gateware/serwb/kusphy.py +++ b/artiq/gateware/serwb/kusphy.py @@ -6,63 +6,6 @@ from migen.genlib.misc import BitSlip from misoc.cores.code_8b10b import Encoder, Decoder -class KUSSerdesPLL(Module): - def __init__(self, refclk_freq, linerate, vco_div=1): - assert refclk_freq == 125e6 - assert linerate == 1.25e9 - - self.lock = Signal() - self.refclk = Signal() - self.serdes_clk = Signal() - self.serdes_20x_clk = Signal() - self.serdes_5x_clk = Signal() - - # # # - - #---------------------- - # refclk: 125MHz - # vco: 1250MHz - #---------------------- - # serdes: 31.25MHz - # serdes_20x: 625MHz - # serdes_5x: 156.25MHz - #---------------------- - self.linerate = linerate - - pll_locked = Signal() - pll_fb = Signal() - pll_serdes_clk = Signal() - pll_serdes_20x_clk = Signal() - pll_serdes_5x_clk = Signal() - self.specials += [ - Instance("PLLE2_BASE", - p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, - - # VCO @ 1.25GHz / vco_div - p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=8.0, - p_CLKFBOUT_MULT=10, p_DIVCLK_DIVIDE=vco_div, - i_CLKIN1=self.refclk, i_CLKFBIN=pll_fb, - o_CLKFBOUT=pll_fb, - - # 31.25MHz: serdes - p_CLKOUT0_DIVIDE=40//vco_div, p_CLKOUT0_PHASE=0.0, - o_CLKOUT0=pll_serdes_clk, - - # 625MHz: serdes_20x - p_CLKOUT1_DIVIDE=2//vco_div, p_CLKOUT1_PHASE=0.0, - o_CLKOUT1=pll_serdes_20x_clk, - - # 156.25MHz: serdes_5x - p_CLKOUT2_DIVIDE=8//vco_div, p_CLKOUT2_PHASE=0.0, - o_CLKOUT2=pll_serdes_5x_clk - ), - Instance("BUFG", i_I=pll_serdes_clk, o_O=self.serdes_clk), - Instance("BUFG", i_I=pll_serdes_20x_clk, o_O=self.serdes_20x_clk), - Instance("BUFG", i_I=pll_serdes_5x_clk, o_O=self.serdes_5x_clk) - ] - self.specials += MultiReg(pll_locked, self.lock) - - class KUSSerdes(Module): def __init__(self, pll, pads, mode="master"): self.tx_data = Signal(32) diff --git a/artiq/gateware/serwb/phy.py b/artiq/gateware/serwb/phy.py index 179e141f9..11808a9b3 100644 --- a/artiq/gateware/serwb/phy.py +++ b/artiq/gateware/serwb/phy.py @@ -4,6 +4,9 @@ from migen.genlib.misc import WaitTimer from misoc.interconnect.csr import * +from artiq.gateware.serwb.kusphy import KUSSerdes +from artiq.gateware.serwb.s7phy import S7Serdes + # Master <--> Slave synchronization: # 1) Master sends idle pattern (zeroes) to reset Slave. @@ -13,11 +16,11 @@ from misoc.interconnect.csr import * # 5) Slave stops sending K25.5 commas. # 6) Link is ready. -class SerdesMasterInit(Module): +class _SerdesMasterInit(Module): def __init__(self, serdes, taps): self.reset = Signal() - self.error = Signal() self.ready = Signal() + self.error = Signal() # # # @@ -72,6 +75,7 @@ class SerdesMasterInit(Module): If(serdes.rx_comma, timer.wait.eq(1), If(timer.done, + timer.wait.eq(0), NextValue(delay_min, delay), NextValue(delay_min_found, 1) ) @@ -82,7 +86,7 @@ class SerdesMasterInit(Module): If(~serdes.rx_comma, NextValue(delay_max, delay), NextValue(delay_max_found, 1), - NextState("RESET_SAMPLING_WINDOW") + NextState("CHECK_SAMPLING_WINDOW") ).Else( NextState("INC_DELAY_BITSLIP") ) @@ -93,12 +97,10 @@ class SerdesMasterInit(Module): fsm.act("INC_DELAY_BITSLIP", NextState("WAIT_STABLE"), If(delay == (taps - 1), - If(delay_min_found, - NextState("ERROR") - ), If(bitslip == (40 - 1), - NextValue(bitslip, 0) - ).Else( + NextState("ERROR") + ).Else( + NextValue(delay_min_found, 0), NextValue(bitslip, bitslip + 1) ), NextValue(delay, 0), @@ -110,6 +112,17 @@ class SerdesMasterInit(Module): ), serdes.tx_comma.eq(1) ) + fsm.act("CHECK_SAMPLING_WINDOW", + If((delay_min == 0) | + (delay_max == (taps - 1)) | + ((delay_max - delay_min) < taps//16), + NextValue(delay_min_found, 0), + NextValue(delay_max_found, 0), + NextState("WAIT_STABLE") + ).Else( + NextState("RESET_SAMPLING_WINDOW") + ) + ) fsm.act("RESET_SAMPLING_WINDOW", NextValue(delay, 0), serdes.rx_delay_rst.eq(1), @@ -143,7 +156,7 @@ class SerdesMasterInit(Module): ) -class SerdesSlaveInit(Module, AutoCSR): +class _SerdesSlaveInit(Module, AutoCSR): def __init__(self, serdes, taps): self.reset = Signal() self.ready = Signal() @@ -199,7 +212,7 @@ class SerdesSlaveInit(Module, AutoCSR): If(~serdes.rx_comma, NextValue(delay_max, delay), NextValue(delay_max_found, 1), - NextState("RESET_SAMPLING_WINDOW") + NextState("CHECK_SAMPLING_WINDOW") ).Else( NextState("INC_DELAY_BITSLIP") ) @@ -210,12 +223,10 @@ class SerdesSlaveInit(Module, AutoCSR): fsm.act("INC_DELAY_BITSLIP", NextState("WAIT_STABLE"), If(delay == (taps - 1), - If(delay_min_found, - NextState("ERROR") - ), If(bitslip == (40 - 1), - NextValue(bitslip, 0) - ).Else( + NextState("ERROR") + ).Else( + NextValue(delay_min_found, 0), NextValue(bitslip, bitslip + 1) ), NextValue(delay, 0), @@ -227,6 +238,17 @@ class SerdesSlaveInit(Module, AutoCSR): ), serdes.tx_idle.eq(1) ) + fsm.act("CHECK_SAMPLING_WINDOW", + If((delay_min == 0) | + (delay_max == (taps - 1)) | + ((delay_max - delay_min) < taps//16), + NextValue(delay_min_found, 0), + NextValue(delay_max_found, 0), + NextState("WAIT_STABLE") + ).Else( + NextState("RESET_SAMPLING_WINDOW") + ) + ) fsm.act("RESET_SAMPLING_WINDOW", NextValue(delay, 0), serdes.rx_delay_rst.eq(1), @@ -266,7 +288,7 @@ class SerdesSlaveInit(Module, AutoCSR): ) -class SerdesControl(Module, AutoCSR): +class _SerdesControl(Module, AutoCSR): def __init__(self, init, mode="master"): if mode == "master": self.reset = CSR() @@ -294,3 +316,79 @@ class SerdesControl(Module, AutoCSR): self.delay_max.status.eq(init.delay_max), self.bitslip.status.eq(init.bitslip) ] + + +class SERWBPLL(Module): + def __init__(self, refclk_freq, linerate, vco_div=1): + assert refclk_freq == 125e6 + assert linerate == 1.25e9 + + self.lock = Signal() + self.refclk = Signal() + self.serdes_clk = Signal() + self.serdes_20x_clk = Signal() + self.serdes_5x_clk = Signal() + + # # # + + #---------------------- + # refclk: 125MHz + # vco: 1250MHz + #---------------------- + # serdes: 31.25MHz + # serdes_20x: 625MHz + # serdes_5x: 156.25MHz + #---------------------- + self.linerate = linerate + + pll_locked = Signal() + pll_fb = Signal() + pll_serdes_clk = Signal() + pll_serdes_20x_clk = Signal() + pll_serdes_5x_clk = Signal() + self.specials += [ + Instance("PLLE2_BASE", + p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, + + # VCO @ 1.25GHz / vco_div + p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=8.0, + p_CLKFBOUT_MULT=10, p_DIVCLK_DIVIDE=vco_div, + i_CLKIN1=self.refclk, i_CLKFBIN=pll_fb, + o_CLKFBOUT=pll_fb, + + # 31.25MHz: serdes + p_CLKOUT0_DIVIDE=40//vco_div, p_CLKOUT0_PHASE=0.0, + o_CLKOUT0=pll_serdes_clk, + + # 625MHz: serdes_20x + p_CLKOUT1_DIVIDE=2//vco_div, p_CLKOUT1_PHASE=0.0, + o_CLKOUT1=pll_serdes_20x_clk, + + # 156.25MHz: serdes_5x + p_CLKOUT2_DIVIDE=8//vco_div, p_CLKOUT2_PHASE=0.0, + o_CLKOUT2=pll_serdes_5x_clk + ), + Instance("BUFG", i_I=pll_serdes_clk, o_O=self.serdes_clk), + Instance("BUFG", i_I=pll_serdes_20x_clk, o_O=self.serdes_20x_clk), + Instance("BUFG", i_I=pll_serdes_5x_clk, o_O=self.serdes_5x_clk) + ] + self.specials += MultiReg(pll_locked, self.lock) + + + +class SERWBPHY(Module, AutoCSR): + def __init__(self, device, pll, pads, mode="master"): + assert mode in ["master", "slave"] + if device[:4] == "xcku": + taps = 512 + self.submodules.serdes = KUSSerdes(pll, pads, mode) + elif device[:4] == "xc7a": + taps = 32 + self.submodules.serdes = S7Serdes(pll, pads, mode) + else: + raise NotImplementedError + if mode == "master": + self.submodules.init = _SerdesMasterInit(self.serdes, taps) + else: + self.submodules.init = _SerdesSlaveInit(self.serdes, taps) + self.submodules.control = _SerdesControl(self.init, mode) diff --git a/artiq/gateware/serwb/s7phy.py b/artiq/gateware/serwb/s7phy.py index 2b5a0473c..fd4e2657a 100644 --- a/artiq/gateware/serwb/s7phy.py +++ b/artiq/gateware/serwb/s7phy.py @@ -6,63 +6,6 @@ from migen.genlib.misc import BitSlip from misoc.cores.code_8b10b import Encoder, Decoder -class S7SerdesPLL(Module): - def __init__(self, refclk_freq, linerate, vco_div=1): - assert refclk_freq == 125e6 - assert linerate == 1.25e9 - - self.lock = Signal() - self.refclk = Signal() - self.serdes_clk = Signal() - self.serdes_20x_clk = Signal() - self.serdes_5x_clk = Signal() - - # # # - - #---------------------- - # refclk: 125MHz - # vco: 1250MHz - #---------------------- - # serdes: 31.25MHz - # serdes_20x: 625MHz - # serdes_5x: 156.25MHz - #---------------------- - self.linerate = linerate - - pll_locked = Signal() - pll_fb = Signal() - pll_serdes_clk = Signal() - pll_serdes_20x_clk = Signal() - pll_serdes_5x_clk = Signal() - self.specials += [ - Instance("PLLE2_BASE", - p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, - - # VCO @ 1.25GHz / vco_div - p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=8.0, - p_CLKFBOUT_MULT=10, p_DIVCLK_DIVIDE=vco_div, - i_CLKIN1=self.refclk, i_CLKFBIN=pll_fb, - o_CLKFBOUT=pll_fb, - - # 31.25MHz: serdes - p_CLKOUT0_DIVIDE=40//vco_div, p_CLKOUT0_PHASE=0.0, - o_CLKOUT0=pll_serdes_clk, - - # 625MHz: serdes_20x - p_CLKOUT1_DIVIDE=2//vco_div, p_CLKOUT1_PHASE=0.0, - o_CLKOUT1=pll_serdes_20x_clk, - - # 156.25MHz: serdes_5x - p_CLKOUT2_DIVIDE=8//vco_div, p_CLKOUT2_PHASE=0.0, - o_CLKOUT2=pll_serdes_5x_clk - ), - Instance("BUFG", i_I=pll_serdes_clk, o_O=self.serdes_clk), - Instance("BUFG", i_I=pll_serdes_20x_clk, o_O=self.serdes_20x_clk), - Instance("BUFG", i_I=pll_serdes_5x_clk, o_O=self.serdes_5x_clk) - ] - self.specials += MultiReg(pll_locked, self.lock) - - class S7Serdes(Module): def __init__(self, pll, pads, mode="master"): self.tx_data = Signal(32)