mirror of https://github.com/m-labs/artiq.git
gateware/serwb: SERWBPLL, SERWBPHY, SERWBCore and add checks in delay finding to verify the sampling window
This commit is contained in:
parent
9ba50098a8
commit
41d57d64f6
|
@ -1 +1 @@
|
||||||
from artiq.gateware.serwb import s7phy, kusphy, phy, packet, etherbone
|
from artiq.gateware.serwb import s7phy, kusphy, phy, core, packet, etherbone
|
||||||
|
|
|
@ -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),
|
||||||
|
]
|
|
@ -18,7 +18,7 @@ from misoc.interconnect import wishbone
|
||||||
from artiq.gateware.serwb.packet import *
|
from artiq.gateware.serwb.packet import *
|
||||||
|
|
||||||
|
|
||||||
class Packetizer(Module):
|
class _Packetizer(Module):
|
||||||
def __init__(self, sink_description, source_description, header):
|
def __init__(self, sink_description, source_description, header):
|
||||||
self.sink = sink = stream.Endpoint(sink_description)
|
self.sink = sink = stream.Endpoint(sink_description)
|
||||||
self.source = source = stream.Endpoint(source_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):
|
def __init__(self, sink_description, source_description, header):
|
||||||
self.sink = sink = stream.Endpoint(sink_description)
|
self.sink = sink = stream.Endpoint(sink_description)
|
||||||
self.source = source = stream.Endpoint(source_description)
|
self.source = source = stream.Endpoint(source_description)
|
||||||
|
@ -275,22 +275,22 @@ def etherbone_mmap_description(dw):
|
||||||
|
|
||||||
# etherbone packet
|
# etherbone packet
|
||||||
|
|
||||||
class EtherbonePacketPacketizer(Packetizer):
|
class _EtherbonePacketPacketizer(_Packetizer):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Packetizer.__init__(self,
|
_Packetizer.__init__(self,
|
||||||
etherbone_packet_description(32),
|
etherbone_packet_description(32),
|
||||||
user_description(32),
|
user_description(32),
|
||||||
etherbone_packet_header)
|
etherbone_packet_header)
|
||||||
|
|
||||||
|
|
||||||
class EtherbonePacketTX(Module):
|
class _EtherbonePacketTX(Module):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.sink = sink = stream.Endpoint(etherbone_packet_user_description(32))
|
self.sink = sink = stream.Endpoint(etherbone_packet_user_description(32))
|
||||||
self.source = source = stream.Endpoint(user_description(32))
|
self.source = source = stream.Endpoint(user_description(32))
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
self.submodules.packetizer = packetizer = EtherbonePacketPacketizer()
|
self.submodules.packetizer = packetizer = _EtherbonePacketPacketizer()
|
||||||
self.comb += [
|
self.comb += [
|
||||||
packetizer.sink.stb.eq(sink.stb),
|
packetizer.sink.stb.eq(sink.stb),
|
||||||
packetizer.sink.eop.eq(sink.eop),
|
packetizer.sink.eop.eq(sink.eop),
|
||||||
|
@ -321,22 +321,22 @@ class EtherbonePacketTX(Module):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class EtherbonePacketDepacketizer(Depacketizer):
|
class _EtherbonePacketDepacketizer(_Depacketizer):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Depacketizer.__init__(self,
|
_Depacketizer.__init__(self,
|
||||||
user_description(32),
|
user_description(32),
|
||||||
etherbone_packet_description(32),
|
etherbone_packet_description(32),
|
||||||
etherbone_packet_header)
|
etherbone_packet_header)
|
||||||
|
|
||||||
|
|
||||||
class EtherbonePacketRX(Module):
|
class _EtherbonePacketRX(Module):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.sink = sink = stream.Endpoint(user_description(32))
|
self.sink = sink = stream.Endpoint(user_description(32))
|
||||||
self.source = source = stream.Endpoint(etherbone_packet_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.comb += sink.connect(depacketizer.sink)
|
||||||
|
|
||||||
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
|
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):
|
def __init__(self, port_sink, port_source):
|
||||||
self.submodules.tx = tx = EtherbonePacketTX()
|
self.submodules.tx = tx = _EtherbonePacketTX()
|
||||||
self.submodules.rx = rx = EtherbonePacketRX()
|
self.submodules.rx = rx = _EtherbonePacketRX()
|
||||||
self.comb += [
|
self.comb += [
|
||||||
tx.source.connect(port_sink),
|
tx.source.connect(port_sink),
|
||||||
port_source.connect(rx.sink)
|
port_source.connect(rx.sink)
|
||||||
|
@ -397,23 +397,23 @@ class EtherbonePacket(Module):
|
||||||
|
|
||||||
# etherbone record
|
# etherbone record
|
||||||
|
|
||||||
class EtherboneRecordPacketizer(Packetizer):
|
class _EtherboneRecordPacketizer(_Packetizer):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Packetizer.__init__(self,
|
_Packetizer.__init__(self,
|
||||||
etherbone_record_description(32),
|
etherbone_record_description(32),
|
||||||
etherbone_packet_user_description(32),
|
etherbone_packet_user_description(32),
|
||||||
etherbone_record_header)
|
etherbone_record_header)
|
||||||
|
|
||||||
|
|
||||||
class EtherboneRecordDepacketizer(Depacketizer):
|
class _EtherboneRecordDepacketizer(_Depacketizer):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Depacketizer.__init__(self,
|
_Depacketizer.__init__(self,
|
||||||
etherbone_packet_user_description(32),
|
etherbone_packet_user_description(32),
|
||||||
etherbone_record_description(32),
|
etherbone_record_description(32),
|
||||||
etherbone_record_header)
|
etherbone_record_header)
|
||||||
|
|
||||||
|
|
||||||
class EtherboneRecordReceiver(Module):
|
class _EtherboneRecordReceiver(Module):
|
||||||
def __init__(self, buffer_depth=256):
|
def __init__(self, buffer_depth=256):
|
||||||
self.sink = sink = stream.Endpoint(etherbone_record_description(32))
|
self.sink = sink = stream.Endpoint(etherbone_record_description(32))
|
||||||
self.source = source = stream.Endpoint(etherbone_mmap_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):
|
def __init__(self, buffer_depth=256):
|
||||||
self.sink = sink = stream.Endpoint(etherbone_mmap_description(32))
|
self.sink = sink = stream.Endpoint(etherbone_mmap_description(32))
|
||||||
self.source = source = stream.Endpoint(etherbone_record_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):
|
def __init__(self):
|
||||||
self.sink = sink = stream.Endpoint(etherbone_packet_user_description(32))
|
self.sink = sink = stream.Endpoint(etherbone_packet_user_description(32))
|
||||||
self.source = source = 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
|
# receive record, decode it and generate mmap stream
|
||||||
self.submodules.depacketizer = depacketizer = EtherboneRecordDepacketizer()
|
self.submodules.depacketizer = depacketizer = _EtherboneRecordDepacketizer()
|
||||||
self.submodules.receiver = receiver = EtherboneRecordReceiver()
|
self.submodules.receiver = receiver = _EtherboneRecordReceiver()
|
||||||
self.comb += [
|
self.comb += [
|
||||||
sink.connect(depacketizer.sink),
|
sink.connect(depacketizer.sink),
|
||||||
depacketizer.source.connect(receiver.sink)
|
depacketizer.source.connect(receiver.sink)
|
||||||
]
|
]
|
||||||
|
|
||||||
# receive mmap stream, encode it and send records
|
# receive mmap stream, encode it and send records
|
||||||
self.submodules.sender = sender = EtherboneRecordSender()
|
self.submodules.sender = sender = _EtherboneRecordSender()
|
||||||
self.submodules.packetizer = packetizer = EtherboneRecordPacketizer()
|
self.submodules.packetizer = packetizer = _EtherboneRecordPacketizer()
|
||||||
self.comb += [
|
self.comb += [
|
||||||
sender.source.connect(packetizer.sink),
|
sender.source.connect(packetizer.sink),
|
||||||
packetizer.source.connect(source),
|
packetizer.source.connect(source),
|
||||||
|
@ -574,7 +574,7 @@ class EtherboneRecord(Module):
|
||||||
|
|
||||||
# etherbone wishbone
|
# etherbone wishbone
|
||||||
|
|
||||||
class EtherboneWishboneMaster(Module):
|
class _EtherboneWishboneMaster(Module):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.sink = sink = stream.Endpoint(etherbone_mmap_description(32))
|
self.sink = sink = stream.Endpoint(etherbone_mmap_description(32))
|
||||||
self.source = source = 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):
|
def __init__(self):
|
||||||
self.bus = bus = wishbone.Interface()
|
self.bus = bus = wishbone.Interface()
|
||||||
self.ready = Signal(reset=1)
|
self.ready = Signal(reset=1)
|
||||||
|
@ -723,12 +723,12 @@ class Etherbone(Module):
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
self.submodules.packet = EtherbonePacket(source, sink)
|
self.submodules.packet = _EtherbonePacket(source, sink)
|
||||||
self.submodules.record = EtherboneRecord()
|
self.submodules.record = _EtherboneRecord()
|
||||||
if mode == "master":
|
if mode == "master":
|
||||||
self.submodules.wishbone = EtherboneWishboneMaster()
|
self.submodules.wishbone = _EtherboneWishboneMaster()
|
||||||
elif mode == "slave":
|
elif mode == "slave":
|
||||||
self.submodules.wishbone = EtherboneWishboneSlave()
|
self.submodules.wishbone = _EtherboneWishboneSlave()
|
||||||
else:
|
else:
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
|
|
|
@ -6,63 +6,6 @@ from migen.genlib.misc import BitSlip
|
||||||
from misoc.cores.code_8b10b import Encoder, Decoder
|
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):
|
class KUSSerdes(Module):
|
||||||
def __init__(self, pll, pads, mode="master"):
|
def __init__(self, pll, pads, mode="master"):
|
||||||
self.tx_data = Signal(32)
|
self.tx_data = Signal(32)
|
||||||
|
|
|
@ -4,6 +4,9 @@ from migen.genlib.misc import WaitTimer
|
||||||
|
|
||||||
from misoc.interconnect.csr import *
|
from misoc.interconnect.csr import *
|
||||||
|
|
||||||
|
from artiq.gateware.serwb.kusphy import KUSSerdes
|
||||||
|
from artiq.gateware.serwb.s7phy import S7Serdes
|
||||||
|
|
||||||
|
|
||||||
# Master <--> Slave synchronization:
|
# Master <--> Slave synchronization:
|
||||||
# 1) Master sends idle pattern (zeroes) to reset Slave.
|
# 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.
|
# 5) Slave stops sending K25.5 commas.
|
||||||
# 6) Link is ready.
|
# 6) Link is ready.
|
||||||
|
|
||||||
class SerdesMasterInit(Module):
|
class _SerdesMasterInit(Module):
|
||||||
def __init__(self, serdes, taps):
|
def __init__(self, serdes, taps):
|
||||||
self.reset = Signal()
|
self.reset = Signal()
|
||||||
self.error = Signal()
|
|
||||||
self.ready = Signal()
|
self.ready = Signal()
|
||||||
|
self.error = Signal()
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
|
@ -72,6 +75,7 @@ class SerdesMasterInit(Module):
|
||||||
If(serdes.rx_comma,
|
If(serdes.rx_comma,
|
||||||
timer.wait.eq(1),
|
timer.wait.eq(1),
|
||||||
If(timer.done,
|
If(timer.done,
|
||||||
|
timer.wait.eq(0),
|
||||||
NextValue(delay_min, delay),
|
NextValue(delay_min, delay),
|
||||||
NextValue(delay_min_found, 1)
|
NextValue(delay_min_found, 1)
|
||||||
)
|
)
|
||||||
|
@ -82,7 +86,7 @@ class SerdesMasterInit(Module):
|
||||||
If(~serdes.rx_comma,
|
If(~serdes.rx_comma,
|
||||||
NextValue(delay_max, delay),
|
NextValue(delay_max, delay),
|
||||||
NextValue(delay_max_found, 1),
|
NextValue(delay_max_found, 1),
|
||||||
NextState("RESET_SAMPLING_WINDOW")
|
NextState("CHECK_SAMPLING_WINDOW")
|
||||||
).Else(
|
).Else(
|
||||||
NextState("INC_DELAY_BITSLIP")
|
NextState("INC_DELAY_BITSLIP")
|
||||||
)
|
)
|
||||||
|
@ -93,12 +97,10 @@ class SerdesMasterInit(Module):
|
||||||
fsm.act("INC_DELAY_BITSLIP",
|
fsm.act("INC_DELAY_BITSLIP",
|
||||||
NextState("WAIT_STABLE"),
|
NextState("WAIT_STABLE"),
|
||||||
If(delay == (taps - 1),
|
If(delay == (taps - 1),
|
||||||
If(delay_min_found,
|
|
||||||
NextState("ERROR")
|
|
||||||
),
|
|
||||||
If(bitslip == (40 - 1),
|
If(bitslip == (40 - 1),
|
||||||
NextValue(bitslip, 0)
|
NextState("ERROR")
|
||||||
).Else(
|
).Else(
|
||||||
|
NextValue(delay_min_found, 0),
|
||||||
NextValue(bitslip, bitslip + 1)
|
NextValue(bitslip, bitslip + 1)
|
||||||
),
|
),
|
||||||
NextValue(delay, 0),
|
NextValue(delay, 0),
|
||||||
|
@ -110,6 +112,17 @@ class SerdesMasterInit(Module):
|
||||||
),
|
),
|
||||||
serdes.tx_comma.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),
|
||||||
|
NextValue(delay_min_found, 0),
|
||||||
|
NextValue(delay_max_found, 0),
|
||||||
|
NextState("WAIT_STABLE")
|
||||||
|
).Else(
|
||||||
|
NextState("RESET_SAMPLING_WINDOW")
|
||||||
|
)
|
||||||
|
)
|
||||||
fsm.act("RESET_SAMPLING_WINDOW",
|
fsm.act("RESET_SAMPLING_WINDOW",
|
||||||
NextValue(delay, 0),
|
NextValue(delay, 0),
|
||||||
serdes.rx_delay_rst.eq(1),
|
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):
|
def __init__(self, serdes, taps):
|
||||||
self.reset = Signal()
|
self.reset = Signal()
|
||||||
self.ready = Signal()
|
self.ready = Signal()
|
||||||
|
@ -199,7 +212,7 @@ class SerdesSlaveInit(Module, AutoCSR):
|
||||||
If(~serdes.rx_comma,
|
If(~serdes.rx_comma,
|
||||||
NextValue(delay_max, delay),
|
NextValue(delay_max, delay),
|
||||||
NextValue(delay_max_found, 1),
|
NextValue(delay_max_found, 1),
|
||||||
NextState("RESET_SAMPLING_WINDOW")
|
NextState("CHECK_SAMPLING_WINDOW")
|
||||||
).Else(
|
).Else(
|
||||||
NextState("INC_DELAY_BITSLIP")
|
NextState("INC_DELAY_BITSLIP")
|
||||||
)
|
)
|
||||||
|
@ -210,12 +223,10 @@ class SerdesSlaveInit(Module, AutoCSR):
|
||||||
fsm.act("INC_DELAY_BITSLIP",
|
fsm.act("INC_DELAY_BITSLIP",
|
||||||
NextState("WAIT_STABLE"),
|
NextState("WAIT_STABLE"),
|
||||||
If(delay == (taps - 1),
|
If(delay == (taps - 1),
|
||||||
If(delay_min_found,
|
|
||||||
NextState("ERROR")
|
|
||||||
),
|
|
||||||
If(bitslip == (40 - 1),
|
If(bitslip == (40 - 1),
|
||||||
NextValue(bitslip, 0)
|
NextState("ERROR")
|
||||||
).Else(
|
).Else(
|
||||||
|
NextValue(delay_min_found, 0),
|
||||||
NextValue(bitslip, bitslip + 1)
|
NextValue(bitslip, bitslip + 1)
|
||||||
),
|
),
|
||||||
NextValue(delay, 0),
|
NextValue(delay, 0),
|
||||||
|
@ -227,6 +238,17 @@ class SerdesSlaveInit(Module, AutoCSR):
|
||||||
),
|
),
|
||||||
serdes.tx_idle.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),
|
||||||
|
NextValue(delay_min_found, 0),
|
||||||
|
NextValue(delay_max_found, 0),
|
||||||
|
NextState("WAIT_STABLE")
|
||||||
|
).Else(
|
||||||
|
NextState("RESET_SAMPLING_WINDOW")
|
||||||
|
)
|
||||||
|
)
|
||||||
fsm.act("RESET_SAMPLING_WINDOW",
|
fsm.act("RESET_SAMPLING_WINDOW",
|
||||||
NextValue(delay, 0),
|
NextValue(delay, 0),
|
||||||
serdes.rx_delay_rst.eq(1),
|
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"):
|
def __init__(self, init, mode="master"):
|
||||||
if mode == "master":
|
if mode == "master":
|
||||||
self.reset = CSR()
|
self.reset = CSR()
|
||||||
|
@ -294,3 +316,79 @@ class SerdesControl(Module, AutoCSR):
|
||||||
self.delay_max.status.eq(init.delay_max),
|
self.delay_max.status.eq(init.delay_max),
|
||||||
self.bitslip.status.eq(init.bitslip)
|
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)
|
||||||
|
|
|
@ -6,63 +6,6 @@ from migen.genlib.misc import BitSlip
|
||||||
from misoc.cores.code_8b10b import Encoder, Decoder
|
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):
|
class S7Serdes(Module):
|
||||||
def __init__(self, pll, pads, mode="master"):
|
def __init__(self, pll, pads, mode="master"):
|
||||||
self.tx_data = Signal(32)
|
self.tx_data = Signal(32)
|
||||||
|
|
Loading…
Reference in New Issue