Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/artiq
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: ae3a52c49c20
Choose a base ref
...
head repository: m-labs/artiq
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: bdee914828c1
Choose a head ref
  • 4 commits
  • 3 files changed
  • 1 contributor

Commits on Jul 28, 2015

  1. Copy the full SHA
    9ac5bc5 View commit details
  2. Copy the full SHA
    8e92cc9 View commit details
  3. Copy the full SHA
    e95b06e View commit details
  4. Copy the full SHA
    bdee914 View commit details
Showing with 235 additions and 45 deletions.
  1. +155 −0 artiq/gateware/rtio/phy/ttl_serdes_spartan6.py
  2. +0 −12 soc/runtime/rtiocrg.c
  3. +80 −33 soc/targets/artiq_pipistrello.py
155 changes: 155 additions & 0 deletions artiq/gateware/rtio/phy/ttl_serdes_spartan6.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
from migen.fhdl.std import *

from artiq.gateware.rtio.phy import ttl_serdes_generic


class _OSERDES2_8X(Module):
def __init__(self, pad, stb):
self.o = Signal(8)
self.t_in = Signal()
self.t_out = Signal()

# # #

cascade = Signal(4)
o = self.o
common = dict(p_DATA_RATE_OQ="SDR", p_DATA_RATE_OT="SDR",
p_DATA_WIDTH=8, p_OUTPUT_MODE="SINGLE_ENDED", i_TRAIN=0,
i_CLK0=ClockSignal("rtiox8"), i_CLK1=0,
i_CLKDIV=ClockSignal("rio_phy"),
i_IOCE=stb, i_OCE=1, i_TCE=1, i_RST=0,
i_T4=self.t_in, i_T3=self.t_in,
i_T2=self.t_in, i_T1=self.t_in)

self.specials += [
Instance("OSERDES2", p_SERDES_MODE="MASTER",
i_D4=o[7], i_D3=o[6], i_D2=o[5], i_D1=o[4],
i_SHIFTIN1=1, i_SHIFTIN2=1,
i_SHIFTIN3=cascade[2], i_SHIFTIN4=cascade[3],
o_SHIFTOUT1=cascade[0], o_SHIFTOUT2=cascade[1],
o_OQ=pad, o_TQ=self.t_out, **common),
Instance("OSERDES2", p_SERDES_MODE="SLAVE",
i_D4=o[3], i_D3=o[2], i_D2=o[1], i_D1=o[0],
i_SHIFTIN1=cascade[0], i_SHIFTIN2=cascade[1],
i_SHIFTIN3=1, i_SHIFTIN4=1,
o_SHIFTOUT3=cascade[2], o_SHIFTOUT4=cascade[3],
**common),
]


class _IOSERDES2_8X(Module):
def __init__(self, pad, stb):
self.o = Signal(8)
self.i = Signal(8)
self.oe = Signal()

# # #

pad_i = Signal()
pad_o = Signal()
cascade = Signal()
i = self.i
common = dict(p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR",
p_DATA_WIDTH=8, p_INTERFACE_TYPE="RETIMED",
i_BITSLIP=0, i_CE0=1, i_IOCE=stb,
i_RST=0, i_CLK0=ClockSignal("rtiox8"), i_CLK1=0,
i_CLKDIV=ClockSignal("rio_phy"))
self.specials += [
Instance("ISERDES2", p_SERDES_MODE="MASTER",
o_Q4=i[7], o_Q3=i[6], o_Q2=i[5], o_Q1=i[4],
o_SHIFTOUT=cascade, i_D=pad_i, i_SHIFTIN=0,
**common),
Instance("ISERDES2", p_SERDES_MODE="SLAVE",
o_Q4=i[3], o_Q3=i[2], o_Q2=i[1], o_Q1=i[0],
i_D=0, i_SHIFTIN=cascade, **common),
]

oserdes = _OSERDES2_8X(pad_o, stb)
self.submodules += oserdes
self.specials += Instance("IOBUF",
i_I=pad_o, o_O=pad_i, i_T=oserdes.t_out,
io_IO=pad)
self.comb += [
oserdes.t_in.eq(~self.oe),
oserdes.o.eq(self.o),
]


class Output_8X(ttl_serdes_generic.Output):
def __init__(self, pad, stb):
serdes = _OSERDES2_8X(pad, stb)
self.submodules += serdes
ttl_serdes_generic.Output.__init__(self, serdes)


class Inout_8X(ttl_serdes_generic.Inout):
def __init__(self, pad, stb):
serdes = _IOSERDES2_8X(pad, stb)
self.submodules += serdes
ttl_serdes_generic.Inout.__init__(self, serdes)


class _OSERDES2_4X(Module):
def __init__(self, pad, stb):
self.o = Signal(4)
self.t_in = Signal()
self.t_out = Signal()

# # #

o = self.o
self.specials += Instance("OSERDES2", p_SERDES_MODE="NONE",
p_DATA_RATE_OQ="SDR", p_DATA_RATE_OT="SDR",
p_DATA_WIDTH=4, p_OUTPUT_MODE="SINGLE_ENDED",
i_TRAIN=0, i_CLK0=ClockSignal("rtiox4"),
i_CLK1=0, i_CLKDIV=ClockSignal("rio_phy"),
i_IOCE=stb, i_OCE=1, i_TCE=1,
i_RST=ResetSignal(),
i_T4=self.t_in, i_T3=self.t_in,
i_T2=self.t_in, i_T1=self.t_in,
i_D4=o[3], i_D3=o[2], i_D2=o[1], i_D1=o[0],
o_OQ=pad, o_TQ=self.t_out)


class _IOSERDES2_4X(Module):
def __init__(self, pad, stb):
self.o = Signal(4)
self.i = Signal(4)
self.oe = Signal()

# # #

pad_i = Signal()
pad_o = Signal()
i = self.i
self.specials += Instance("ISERDES2", p_SERDES_MODE="NONE",
p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR",
p_DATA_WIDTH=4, p_INTERFACE_TYPE="RETIMED",
i_BITSLIP=0, i_CE0=1, i_IOCE=stb,
i_RST=0, i_CLK0=ClockSignal("rtiox4"),
i_CLK1=0, i_CLKDIV=ClockSignal("rio_phy"),
o_Q4=i[3], o_Q3=i[2], o_Q2=i[1], o_Q1=i[0],
i_D=pad_i, i_SHIFTIN=0)
oserdes = _OSERDES2_4X(pad_o, stb)
self.submodules += oserdes
self.specials += Instance("IOBUF",
i_I=pad_o, o_O=pad_i, i_T=oserdes.t_out,
io_IO=pad)
self.comb += [
oserdes.t_in.eq(~self.oe),
oserdes.o.eq(self.o),
]


class Output_4X(ttl_serdes_generic.Output):
def __init__(self, pad, stb):
serdes = _OSERDES2_4X(pad, stb)
self.submodules += serdes
ttl_serdes_generic.Output.__init__(self, serdes)


class Inout_4X(ttl_serdes_generic.Inout):
def __init__(self, pad, stb):
serdes = _IOSERDES2_4X(pad, stb)
self.submodules += serdes
ttl_serdes_generic.Inout.__init__(self, serdes)
12 changes: 0 additions & 12 deletions soc/runtime/rtiocrg.c
Original file line number Diff line number Diff line change
@@ -10,9 +10,7 @@ void rtiocrg_init(void)
char b;
int clk;

#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR
rtio_crg_pll_reset_write(0);
#endif
b = 'i';
clk = 0;
fs_read("startup_clock", &b, 1, NULL);
@@ -33,11 +31,7 @@ void rtiocrg_init(void)

int rtiocrg_check(void)
{
#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR
return rtio_crg_pll_locked_read();
#else
return 1;
#endif
}

int rtiocrg_switch_clock(int clk)
@@ -46,22 +40,16 @@ int rtiocrg_switch_clock(int clk)

current_clk = rtio_crg_clock_sel_read();
if(clk == current_clk) {
#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR
busywait_us(150);
if(!rtio_crg_pll_locked_read())
return 0;
#endif
return 1;
}
#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR
rtio_crg_pll_reset_write(1);
#endif
rtio_crg_clock_sel_write(clk);
#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR
rtio_crg_pll_reset_write(0);
busywait_us(150);
if(!rtio_crg_pll_locked_read())
return 0;
#endif
return 1;
}
113 changes: 80 additions & 33 deletions soc/targets/artiq_pipistrello.py
Original file line number Diff line number Diff line change
@@ -3,6 +3,8 @@
from migen.fhdl.std import *
from migen.bank.description import *
from migen.bank import wbgen
from migen.genlib.resetsync import AsyncResetSynchronizer
from migen.genlib.cdc import MultiReg

from misoclib.com import gpio
from misoclib.soc import mem_decoder
@@ -11,46 +13,84 @@

from artiq.gateware.soc import AMPSoC
from artiq.gateware import rtio, nist_qc1
from artiq.gateware.rtio.phy import ttl_simple, dds
from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_spartan6, dds


class _RTIOCRG(Module, AutoCSR):
def __init__(self, platform, clk_freq):
self._clock_sel = CSRStorage()
self.clock_domains.cd_rtio = ClockDomain(reset_less=True)
self._pll_reset = CSRStorage(reset=1)
self._pll_locked = CSRStatus()

f = Fraction(125*1000*1000, clk_freq)
self.clock_domains.cd_rtio = ClockDomain()
self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True)
self.clock_domains.cd_rtiox8 = ClockDomain(reset_less=True)
self.rtiox4_stb = Signal()
self.rtiox8_stb = Signal()

rtio_f = 125*1000*1000
f = Fraction(rtio_f, clk_freq)
rtio_internal_clk = Signal()
self.specials += Instance("DCM_CLKGEN",
p_CLKFXDV_DIVIDE=2,
p_CLKFX_DIVIDE=f.denominator,
p_CLKFX_MD_MAX=float(f),
p_CLKFX_MULTIPLY=f.numerator,
p_CLKIN_PERIOD=1e9/clk_freq,
p_SPREAD_SPECTRUM="NONE",
p_STARTUP_WAIT="FALSE",
i_CLKIN=ClockSignal(),
o_CLKFX=rtio_internal_clk,
i_FREEZEDCM=0,
i_RST=ResetSignal())

rtio_external_clk = platform.request("pmt", 2)
# ISE infers constraints for the internal clock
# and propagates them through the BUFGMUX. Adding this:
# platform.add_period_constraint(rtio_external_clk, 8.0)
# seems to confuse it
self.specials += Instance("BUFGMUX",
i_I0=rtio_internal_clk,
i_I1=rtio_external_clk,
i_S=self._clock_sel.storage,
o_O=self.cd_rtio.clk)
rtio_external_clk = Signal()
pmt2 = platform.request("pmt", 2)
dcm_locked = Signal()
rtio_clk = Signal()
pll_locked = Signal()
pll = Signal(3)
pll_fb = Signal()
self.specials += [
Instance("IBUFG", i_I=pmt2, o_O=rtio_external_clk),
Instance("DCM_CLKGEN", p_CLKFXDV_DIVIDE=2,
p_CLKFX_DIVIDE=f.denominator, p_CLKFX_MD_MAX=float(f),
p_CLKFX_MULTIPLY=f.numerator, p_CLKIN_PERIOD=1e9/clk_freq,
p_SPREAD_SPECTRUM="NONE", p_STARTUP_WAIT="FALSE",
i_CLKIN=ClockSignal(), o_CLKFX=rtio_internal_clk,
i_FREEZEDCM=0, i_RST=ResetSignal(), o_LOCKED=dcm_locked),
Instance("BUFGMUX",
i_I0=rtio_internal_clk, i_I1=rtio_external_clk,
i_S=self._clock_sel.storage, o_O=rtio_clk),
Instance("PLL_ADV", p_SIM_DEVICE="SPARTAN6",
p_BANDWIDTH="OPTIMIZED", p_COMPENSATION="INTERNAL",
p_REF_JITTER=.01, p_CLK_FEEDBACK="CLKFBOUT",
i_DADDR=0, i_DCLK=0, i_DEN=0, i_DI=0, i_DWE=0,
i_RST=self._pll_reset.storage | ~dcm_locked, i_REL=0,
p_DIVCLK_DIVIDE=1, p_CLKFBOUT_MULT=8,
p_CLKFBOUT_PHASE=0., i_CLKINSEL=1,
i_CLKIN1=rtio_clk, i_CLKIN2=0,
p_CLKIN1_PERIOD=1e9/rtio_f, p_CLKIN2_PERIOD=0.,
i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, o_LOCKED=pll_locked,
o_CLKOUT0=pll[0], p_CLKOUT0_DUTY_CYCLE=.5,
o_CLKOUT1=pll[1], p_CLKOUT1_DUTY_CYCLE=.5,
o_CLKOUT2=pll[2], p_CLKOUT2_DUTY_CYCLE=.5,
p_CLKOUT0_PHASE=0., p_CLKOUT0_DIVIDE=1,
p_CLKOUT1_PHASE=0., p_CLKOUT1_DIVIDE=2,
p_CLKOUT2_PHASE=0., p_CLKOUT2_DIVIDE=8),
Instance("BUFPLL", p_DIVIDE=8,
i_PLLIN=pll[0], i_GCLK=self.cd_rtio.clk,
i_LOCKED=pll_locked, o_IOCLK=self.cd_rtiox8.clk,
o_SERDESSTROBE=self.rtiox8_stb),
Instance("BUFPLL", p_DIVIDE=4,
i_PLLIN=pll[1], i_GCLK=self.cd_rtio.clk,
i_LOCKED=pll_locked, o_IOCLK=self.cd_rtiox4.clk,
o_SERDESSTROBE=self.rtiox4_stb),
Instance("BUFG", i_I=pll[2], o_O=self.cd_rtio.clk),
AsyncResetSynchronizer(self.cd_rtio, ~pll_locked),
MultiReg(pll_locked, self._pll_locked.status),
]

# ISE infers correct period constraints for cd_rtio.clk from
# the internal clock. The first two TIGs target just the BUFGMUX.
platform.add_platform_command("""
NET "{int_clk}" TNM_NET = "GRPint_clk";
NET "sys_clk" TNM_NET = "GRPsys_clk";
TIMESPEC "TSfix_ise1" = FROM "GRPint_clk" TO "GRPsys_clk" TIG;
NET "{ext_clk}" TNM_NET = "GRPext_clk";
TIMESPEC "TSfix_ise1" = FROM "GRPsys_clk" TO "GRPext_clk" TIG;
NET "{int_clk}" TNM_NET = "GRPint_clk";
TIMESPEC "TSfix_ise2" = FROM "GRPsys_clk" TO "GRPint_clk" TIG;
""", int_clk=rtio_internal_clk)
NET "{rtio_clk}" TNM_NET = "GRPrtio_clk";
TIMESPEC "TSfix_ise3" = FROM "GRPrtio_clk" TO "GRPsys_clk" TIG;
TIMESPEC "TSfix_ise4" = FROM "GRPsys_clk" TO "GRPrtio_clk" TIG;
""", ext_clk=rtio_external_clk, int_clk=rtio_internal_clk,
rtio_clk=self.cd_rtio.clk)


class NIST_QC1(BaseSoC, AMPSoC):
@@ -90,16 +130,22 @@ def __init__(self, platform, cpu_type="or1k", **kwargs):
platform.request("ttl_h_tx_en").eq(1)
]

self.submodules.rtio_crg = _RTIOCRG(platform, self.clk_freq)

# RTIO channels
rtio_channels = []
# pmt1 can run on a 8x serdes if pmt0 is not used
for i in range(2):
phy = ttl_simple.Inout(platform.request("pmt", i))
phy = ttl_serdes_spartan6.Inout_4X(platform.request("pmt", i),
self.rtio_crg.rtiox4_stb)
self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512,
ofifo_depth=4))

# ttl2 can run on a 8x serdes if xtrig is not used
for i in range(15):
phy = ttl_simple.Output(platform.request("ttl", i))
phy = ttl_serdes_spartan6.Output_4X(platform.request("ttl", i),
self.rtio_crg.rtiox4_stb)
self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=256))

@@ -120,14 +166,15 @@ def __init__(self, platform, cpu_type="or1k", **kwargs):
self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels))
self.add_constant("DDS_CHANNEL_COUNT", 8)
self.add_constant("DDS_AD9858")
phy = dds.AD9858(platform.request("dds"), 8)
dds_pins = platform.request("dds")
self.comb += dds_pins.p.eq(0)
phy = dds.AD9858(dds_pins, 8)
self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy,
ofifo_depth=512,
ififo_depth=4))

# RTIO core
self.submodules.rtio_crg = _RTIOCRG(platform, self.clk_freq)
self.submodules.rtio = rtio.RTIO(rtio_channels)
self.add_constant("RTIO_FINE_TS_WIDTH", self.rtio.fine_ts_width)
self.add_constant("DDS_RTIO_CLK_RATIO", 8 >> self.rtio.fine_ts_width)