ttl_serdes_ultrascale: configurable SERDES ratio. Also try X4 on Sayma

This commit is contained in:
Sebastien Bourdeauducq 2018-03-21 13:01:38 +08:00
parent 9c2d343052
commit f8c2d54e75
2 changed files with 39 additions and 38 deletions

View File

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

View File

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