forked from M-Labs/artiq
ttl_serdes_ultrascale: configurable SERDES ratio. Also try X4 on Sayma
This commit is contained in:
parent
9c2d343052
commit
f8c2d54e75
|
@ -6,10 +6,9 @@ from artiq.gateware.rtio.phy import ttl_serdes_generic
|
||||||
# SERDES clocks are in dedicated domains to make the implementation
|
# SERDES clocks are in dedicated domains to make the implementation
|
||||||
# of the convoluted clocking schemes from AR#67885 less tedious.
|
# of the convoluted clocking schemes from AR#67885 less tedious.
|
||||||
|
|
||||||
|
class _OSERDESE3(Module):
|
||||||
class _OSERDESE2_8X(Module):
|
def __init__(self, dw, pad, pad_n=None):
|
||||||
def __init__(self, pad, pad_n=None):
|
self.o = Signal(dw)
|
||||||
self.o = Signal(8)
|
|
||||||
self.t_in = Signal()
|
self.t_in = Signal()
|
||||||
self.t_out = Signal()
|
self.t_out = Signal()
|
||||||
|
|
||||||
|
@ -17,12 +16,12 @@ class _OSERDESE2_8X(Module):
|
||||||
|
|
||||||
pad_o = Signal()
|
pad_o = Signal()
|
||||||
self.specials += Instance("OSERDESE3",
|
self.specials += Instance("OSERDESE3",
|
||||||
p_DATA_WIDTH=8, p_INIT=0,
|
p_DATA_WIDTH=dw, 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=pad_o, o_T_OUT=self.t_out,
|
o_OQ=pad_o, o_T_OUT=self.t_out,
|
||||||
i_RST=ResetSignal("rtio_serdes"),
|
i_RST=ResetSignal("rtio_serdes"),
|
||||||
i_CLK=ClockSignal("rtiox4_serdes"), i_CLKDIV=ClockSignal("rtio_serdes"),
|
i_CLK=ClockSignal("rtiox_serdes"), i_CLKDIV=ClockSignal("rtio_serdes"),
|
||||||
i_D=self.o, i_T=self.t_in)
|
i_D=self.o, i_T=self.t_in)
|
||||||
if pad_n is None:
|
if pad_n is None:
|
||||||
self.comb += pad.eq(pad_o)
|
self.comb += pad.eq(pad_o)
|
||||||
|
@ -35,10 +34,10 @@ class _OSERDESE2_8X(Module):
|
||||||
io_IO=pad, io_IOB=pad_n)
|
io_IO=pad, io_IOB=pad_n)
|
||||||
|
|
||||||
|
|
||||||
class _ISERDESE2_8X(Module):
|
class _ISERDESE3(Module):
|
||||||
def __init__(self, pad, pad_n=None):
|
def __init__(self, dw, pad, pad_n=None):
|
||||||
self.o = Signal(8)
|
self.o = Signal(dw)
|
||||||
self.i = Signal(8)
|
self.i = Signal(dw)
|
||||||
self.oe = Signal()
|
self.oe = Signal()
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
@ -47,15 +46,15 @@ class _ISERDESE2_8X(Module):
|
||||||
self.specials += Instance("ISERDESE3",
|
self.specials += Instance("ISERDESE3",
|
||||||
p_IS_CLK_INVERTED=0,
|
p_IS_CLK_INVERTED=0,
|
||||||
p_IS_CLK_B_INVERTED=1,
|
p_IS_CLK_B_INVERTED=1,
|
||||||
p_DATA_WIDTH=8,
|
p_DATA_WIDTH=dw,
|
||||||
|
|
||||||
i_D=pad_i,
|
i_D=pad_i,
|
||||||
i_RST=ResetSignal("rtio_serdes"),
|
i_RST=ResetSignal("rtio_serdes"),
|
||||||
i_FIFO_RD_EN=0,
|
i_FIFO_RD_EN=0,
|
||||||
i_CLK=ClockSignal("rtiox4_serdes"),
|
i_CLK=ClockSignal("rtiox_serdes"),
|
||||||
i_CLK_B=ClockSignal("rtiox4_serdes"), # locally inverted
|
i_CLK_B=ClockSignal("rtiox_serdes"), # locally inverted
|
||||||
i_CLKDIV=ClockSignal("rtio_serdes"),
|
i_CLKDIV=ClockSignal("rtio_serdes"),
|
||||||
o_Q=Cat(*self.i[::-1]))
|
o_Q=Cat(*[self.i[i] for i in reversed(range(dw))]))
|
||||||
if pad_n is None:
|
if pad_n is None:
|
||||||
self.comb += pad_i.eq(pad)
|
self.comb += pad_i.eq(pad)
|
||||||
else:
|
else:
|
||||||
|
@ -66,18 +65,18 @@ class _ISERDESE2_8X(Module):
|
||||||
io_I=pad, io_IB=pad_n)
|
io_I=pad, io_IB=pad_n)
|
||||||
|
|
||||||
|
|
||||||
class _IOSERDESE2_8X(Module):
|
class _IOSERDESE3(Module):
|
||||||
def __init__(self, pad, pad_n=None):
|
def __init__(self, dw, pad, pad_n=None):
|
||||||
self.o = Signal(8)
|
self.o = Signal(dw)
|
||||||
self.i = Signal(8)
|
self.i = Signal(dw)
|
||||||
self.oe = Signal()
|
self.oe = Signal()
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
pad_i = Signal()
|
pad_i = Signal()
|
||||||
pad_o = Signal()
|
pad_o = Signal()
|
||||||
iserdes = _ISERDESE2_8X(pad_i)
|
iserdes = _ISERDESE3(dw, pad_i)
|
||||||
oserdes = _OSERDESE2_8X(pad_o)
|
oserdes = _OSERDESE3(dw, pad_o)
|
||||||
self.submodules += iserdes, oserdes
|
self.submodules += iserdes, oserdes
|
||||||
if pad_n is None:
|
if pad_n is None:
|
||||||
self.specials += Instance("IOBUF",
|
self.specials += Instance("IOBUF",
|
||||||
|
@ -96,22 +95,22 @@ class _IOSERDESE2_8X(Module):
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class Output_8X(ttl_serdes_generic.Output):
|
class Output(ttl_serdes_generic.Output):
|
||||||
def __init__(self, pad, pad_n=None):
|
def __init__(self, dw, pad, pad_n=None):
|
||||||
serdes = _OSERDESE2_8X(pad, pad_n)
|
serdes = _OSERDESE3(dw, pad, pad_n)
|
||||||
self.submodules += serdes
|
self.submodules += serdes
|
||||||
ttl_serdes_generic.Output.__init__(self, serdes)
|
ttl_serdes_generic.Output.__init__(self, serdes)
|
||||||
|
|
||||||
|
|
||||||
class InOut_8X(ttl_serdes_generic.InOut):
|
class InOut(ttl_serdes_generic.InOut):
|
||||||
def __init__(self, pad, pad_n=None):
|
def __init__(self, dw, pad, pad_n=None):
|
||||||
serdes = _IOSERDESE2_8X(pad, pad_n)
|
serdes = _IOSERDESE3(dw, pad, pad_n)
|
||||||
self.submodules += serdes
|
self.submodules += serdes
|
||||||
ttl_serdes_generic.InOut.__init__(self, serdes)
|
ttl_serdes_generic.InOut.__init__(self, serdes)
|
||||||
|
|
||||||
|
|
||||||
class Input_8X(ttl_serdes_generic.InOut):
|
class Input(ttl_serdes_generic.InOut):
|
||||||
def __init__(self, pad, pad_n=None):
|
def __init__(self, pad, pad_n=None):
|
||||||
serdes = _ISERDESE2_8X(pad, pad_n)
|
serdes = _ISERDESE3(dw, pad, pad_n)
|
||||||
self.submodules += serdes
|
self.submodules += serdes
|
||||||
ttl_serdes_generic.InOut.__init__(self, serdes)
|
ttl_serdes_generic.InOut.__init__(self, serdes)
|
||||||
|
|
|
@ -126,17 +126,18 @@ class AD9154NoSAWG(Module, AutoCSR):
|
||||||
for i in range(len(conv) // len(ramp))))
|
for i in range(len(conv) // len(ramp))))
|
||||||
|
|
||||||
|
|
||||||
|
# Generates a X2 clock that can be used for 4:1 SERDES ratio.
|
||||||
class _RTIOClockMultiplier(Module):
|
class _RTIOClockMultiplier(Module):
|
||||||
def __init__(self, platform, rtio_clk_freq):
|
def __init__(self, platform, rtio_clk_freq):
|
||||||
self.clock_domains.cd_rtio_serdes = ClockDomain()
|
self.clock_domains.cd_rtio_serdes = ClockDomain()
|
||||||
self.clock_domains.cd_rtiox4_serdes = ClockDomain(reset_less=True)
|
self.clock_domains.cd_rtiox_serdes = ClockDomain(reset_less=True)
|
||||||
|
|
||||||
# See "Global Clock Network Deskew Using Two BUFGs" in ug572.
|
# See "Global Clock Network Deskew Using Two BUFGs" in ug572.
|
||||||
# See also AR#67885.
|
# See also AR#67885.
|
||||||
clkfbout = Signal()
|
clkfbout = Signal()
|
||||||
clkfbin = Signal()
|
clkfbin = Signal()
|
||||||
rtio_clk = Signal()
|
rtio_clk = Signal()
|
||||||
rtiox4_clk = Signal()
|
rtiox_clk = Signal()
|
||||||
self.specials += [
|
self.specials += [
|
||||||
Instance("MMCME2_BASE",
|
Instance("MMCME2_BASE",
|
||||||
p_CLKIN1_PERIOD=1e9/rtio_clk_freq,
|
p_CLKIN1_PERIOD=1e9/rtio_clk_freq,
|
||||||
|
@ -148,14 +149,14 @@ class _RTIOClockMultiplier(Module):
|
||||||
o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbin,
|
o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbin,
|
||||||
|
|
||||||
p_CLKOUT1_DIVIDE=8, o_CLKOUT1=rtio_clk,
|
p_CLKOUT1_DIVIDE=8, o_CLKOUT1=rtio_clk,
|
||||||
p_CLKOUT2_DIVIDE=2, o_CLKOUT2=rtiox4_clk,
|
p_CLKOUT2_DIVIDE=4, o_CLKOUT2=rtiox_clk,
|
||||||
),
|
),
|
||||||
Instance("BUFG", name="rtioserdes_bufg_fb",
|
Instance("BUFG", name="rtioserdes_bufg_fb",
|
||||||
i_I=clkfbout, o_O=clkfbin),
|
i_I=clkfbout, o_O=clkfbin),
|
||||||
Instance("BUFG", name="rtioserdes_bufg_div",
|
Instance("BUFG", name="rtioserdes_bufg_div",
|
||||||
i_I=rtio_clk, o_O=self.cd_rtio_serdes.clk),
|
i_I=rtio_clk, o_O=self.cd_rtio_serdes.clk),
|
||||||
Instance("BUFG", name="rtioserdes_bufg",
|
Instance("BUFG", name="rtioserdes_bufg",
|
||||||
i_I=rtiox4_clk, o_O=self.cd_rtiox4_serdes.clk)
|
i_I=rtiox_clk, o_O=self.cd_rtiox_serdes.clk)
|
||||||
]
|
]
|
||||||
self.comb += self.cd_rtio_serdes.rst.eq(ResetSignal("rio_phy"))
|
self.comb += self.cd_rtio_serdes.rst.eq(ResetSignal("rio_phy"))
|
||||||
|
|
||||||
|
@ -238,6 +239,7 @@ class Standalone(MiniSoC, AMPSoC):
|
||||||
self.add_wb_slave(self.mem_map["serwb"], 8192, serwb_core.etherbone.wishbone.bus)
|
self.add_wb_slave(self.mem_map["serwb"], 8192, serwb_core.etherbone.wishbone.bus)
|
||||||
|
|
||||||
# RTIO
|
# RTIO
|
||||||
|
self.submodules.rtio_clkmul = _RTIOClockMultiplier(platform, 150e6)
|
||||||
rtio_channels = []
|
rtio_channels = []
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
phy = ttl_simple.Output(platform.request("user_led", i))
|
phy = ttl_simple.Output(platform.request("user_led", i))
|
||||||
|
@ -245,12 +247,12 @@ class Standalone(MiniSoC, AMPSoC):
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy))
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
sma_io = platform.request("sma_io", 0)
|
sma_io = platform.request("sma_io", 0)
|
||||||
self.comb += sma_io.direction.eq(1)
|
self.comb += sma_io.direction.eq(1)
|
||||||
phy = ttl_simple.Output(sma_io.level)
|
phy = ttl_serdes_ultrascale.Output(4, sma_io.level)
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy))
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
sma_io = platform.request("sma_io", 1)
|
sma_io = platform.request("sma_io", 1)
|
||||||
self.comb += sma_io.direction.eq(0)
|
self.comb += sma_io.direction.eq(0)
|
||||||
phy = ttl_simple.InOut(sma_io.level)
|
phy = ttl_serdes_ultrascale.InOut(4, sma_io.level)
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy))
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
|
|
||||||
|
@ -396,12 +398,12 @@ class Master(MiniSoC, AMPSoC):
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy))
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
sma_io = platform.request("sma_io", 0)
|
sma_io = platform.request("sma_io", 0)
|
||||||
self.comb += sma_io.direction.eq(1)
|
self.comb += sma_io.direction.eq(1)
|
||||||
phy = ttl_serdes_ultrascale.Output_8X(sma_io.level)
|
phy = ttl_serdes_ultrascale.Output(4, sma_io.level)
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy))
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
sma_io = platform.request("sma_io", 1)
|
sma_io = platform.request("sma_io", 1)
|
||||||
self.comb += sma_io.direction.eq(0)
|
self.comb += sma_io.direction.eq(0)
|
||||||
phy = ttl_serdes_ultrascale.InOut_8X(sma_io.level)
|
phy = ttl_serdes_ultrascale.InOut(4, sma_io.level)
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy))
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
|
|
||||||
|
@ -453,12 +455,12 @@ class Satellite(BaseSoC):
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy))
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
sma_io = platform.request("sma_io", 0)
|
sma_io = platform.request("sma_io", 0)
|
||||||
self.comb += sma_io.direction.eq(1)
|
self.comb += sma_io.direction.eq(1)
|
||||||
phy = ttl_serdes_ultrascale.Output_8X(sma_io.level)
|
phy = ttl_serdes_ultrascale.Output(4, sma_io.level)
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy))
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
sma_io = platform.request("sma_io", 1)
|
sma_io = platform.request("sma_io", 1)
|
||||||
self.comb += sma_io.direction.eq(0)
|
self.comb += sma_io.direction.eq(0)
|
||||||
phy = ttl_serdes_ultrascale.InOut_8X(sma_io.level)
|
phy = ttl_serdes_ultrascale.InOut(4, sma_io.level)
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy))
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue