gateware/serwb: SERWBPLL, SERWBPHY, SERWBCore and add checks in delay finding to verify the sampling window

This commit is contained in:
Florent Kermarrec 2017-08-30 14:31:44 +02:00
parent 9ba50098a8
commit 41d57d64f6
6 changed files with 182 additions and 161 deletions

View File

@ -1 +1 @@
from artiq.gateware.serwb import s7phy, kusphy, phy, packet, etherbone
from artiq.gateware.serwb import s7phy, kusphy, phy, core, packet, etherbone

View File

@ -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),
]

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)