forked from M-Labs/artiq
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 *
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue