mirror of https://github.com/m-labs/artiq.git
Merge remote-tracking branch 'harrydrtio/k7-drtio'
This commit is contained in:
commit
ea0c7b6173
|
@ -153,6 +153,8 @@ fn setup_si5324_as_synthesizer() {
|
||||||
let si5324_ref_input = si5324::Input::Ckin2;
|
let si5324_ref_input = si5324::Input::Ckin2;
|
||||||
#[cfg(soc_platform = "metlino")]
|
#[cfg(soc_platform = "metlino")]
|
||||||
let si5324_ref_input = si5324::Input::Ckin2;
|
let si5324_ref_input = si5324::Input::Ckin2;
|
||||||
|
#[cfg(soc_platform = "kc705")]
|
||||||
|
let si5324_ref_input = si5324::Input::Ckin2;
|
||||||
si5324::setup(&SI5324_SETTINGS, si5324_ref_input).expect("cannot initialize Si5324");
|
si5324::setup(&SI5324_SETTINGS, si5324_ref_input).expect("cannot initialize Si5324");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,6 +167,8 @@ pub fn init() {
|
||||||
let si5324_ext_input = si5324::Input::Ckin2;
|
let si5324_ext_input = si5324::Input::Ckin2;
|
||||||
#[cfg(soc_platform = "metlino")]
|
#[cfg(soc_platform = "metlino")]
|
||||||
let si5324_ext_input = si5324::Input::Ckin2;
|
let si5324_ext_input = si5324::Input::Ckin2;
|
||||||
|
#[cfg(soc_platform = "kc705")]
|
||||||
|
let si5324_ext_input = si5324::Input::Ckin2;
|
||||||
match get_rtio_clock_cfg() {
|
match get_rtio_clock_cfg() {
|
||||||
RtioClock::Internal => setup_si5324_as_synthesizer(),
|
RtioClock::Internal => setup_si5324_as_synthesizer(),
|
||||||
RtioClock::External => si5324::bypass(si5324_ext_input).expect("cannot bypass Si5324")
|
RtioClock::External => si5324::bypass(si5324_ext_input).expect("cannot bypass Si5324")
|
||||||
|
|
|
@ -0,0 +1,341 @@
|
||||||
|
from migen import *
|
||||||
|
from migen.genlib.resetsync import AsyncResetSynchronizer
|
||||||
|
|
||||||
|
from misoc.cores.code_8b10b import Encoder, Decoder
|
||||||
|
from misoc.interconnect.csr import *
|
||||||
|
|
||||||
|
from artiq.gateware.drtio.core import TransceiverInterface, ChannelInterface
|
||||||
|
from artiq.gateware.drtio.transceiver.clock_aligner import BruteforceClockAligner
|
||||||
|
from artiq.gateware.drtio.transceiver.gtx_7series_init import *
|
||||||
|
|
||||||
|
|
||||||
|
class GTX_20X(Module):
|
||||||
|
# Settings:
|
||||||
|
# * GTX reference clock @ 125MHz == coarse RTIO frequency
|
||||||
|
# * GTX data width = 20
|
||||||
|
# * GTX PLL frequency @ 2.5GHz
|
||||||
|
# * GTX line rate (TX & RX) @ 2.5Gb/s
|
||||||
|
# * GTX TX/RX USRCLK @ 125MHz == coarse RTIO frequency
|
||||||
|
def __init__(self, refclk, tx_pads, rx_pads, sys_clk_freq, rtio_clk_freq=125e6, tx_mode="single", rx_mode="single"):
|
||||||
|
assert tx_mode in ["single", "master", "slave"]
|
||||||
|
assert rx_mode in ["single", "master", "slave"]
|
||||||
|
|
||||||
|
self.txenable = Signal()
|
||||||
|
self.submodules.encoder = ClockDomainsRenamer("rtio_tx")(
|
||||||
|
Encoder(2, True))
|
||||||
|
self.submodules.decoders = [ClockDomainsRenamer("rtio_rx")(
|
||||||
|
(Decoder(True))) for _ in range(2)]
|
||||||
|
self.rx_ready = Signal()
|
||||||
|
|
||||||
|
# transceiver direct clock outputs
|
||||||
|
# useful to specify clock constraints in a way palatable to Vivado
|
||||||
|
self.txoutclk = Signal()
|
||||||
|
self.rxoutclk = Signal()
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
cpllreset = Signal()
|
||||||
|
cplllock = Signal()
|
||||||
|
# TX generates RTIO clock, init must be in system domain
|
||||||
|
self.submodules.tx_init = tx_init = GTXInit(sys_clk_freq, False, mode=tx_mode)
|
||||||
|
# RX receives restart commands from RTIO domain
|
||||||
|
self.submodules.rx_init = rx_init = ClockDomainsRenamer("rtio_tx")(
|
||||||
|
GTXInit(rtio_clk_freq, True, mode=rx_mode))
|
||||||
|
self.comb += [
|
||||||
|
cpllreset.eq(tx_init.cpllreset),
|
||||||
|
tx_init.cplllock.eq(cplllock),
|
||||||
|
rx_init.cplllock.eq(cplllock)
|
||||||
|
]
|
||||||
|
|
||||||
|
txdata = Signal(20)
|
||||||
|
rxdata = Signal(20)
|
||||||
|
# Note: the following parameters were set after consulting AR45360
|
||||||
|
self.specials += \
|
||||||
|
Instance("GTXE2_CHANNEL",
|
||||||
|
# PMA Attributes
|
||||||
|
p_PMA_RSV=0x00018480,
|
||||||
|
p_PMA_RSV2=0x2050, # PMA_RSV2[5] = 0: Eye scan feature disabled
|
||||||
|
p_PMA_RSV3=0,
|
||||||
|
p_PMA_RSV4=1, # PMA_RSV[4],RX_CM_TRIM[2:0] = 0b1010: Common mode 800mV
|
||||||
|
p_RX_BIAS_CFG=0b000000000100,
|
||||||
|
p_RX_OS_CFG=0b0000010000000,
|
||||||
|
p_RX_CLK25_DIV=5,
|
||||||
|
p_TX_CLK25_DIV=5,
|
||||||
|
|
||||||
|
# Power-Down Attributes
|
||||||
|
p_PD_TRANS_TIME_FROM_P2=0x3c,
|
||||||
|
p_PD_TRANS_TIME_NONE_P2=0x3c,
|
||||||
|
p_PD_TRANS_TIME_TO_P2=0x64,
|
||||||
|
|
||||||
|
# CPLL
|
||||||
|
p_CPLL_CFG=0xBC07DC,
|
||||||
|
p_CPLL_FBDIV=4,
|
||||||
|
p_CPLL_FBDIV_45=5,
|
||||||
|
p_CPLL_REFCLK_DIV=1,
|
||||||
|
p_RXOUT_DIV=2,
|
||||||
|
p_TXOUT_DIV=2,
|
||||||
|
i_CPLLRESET=cpllreset,
|
||||||
|
i_CPLLPD=cpllreset,
|
||||||
|
o_CPLLLOCK=cplllock,
|
||||||
|
i_CPLLLOCKEN=1,
|
||||||
|
i_CPLLREFCLKSEL=0b001,
|
||||||
|
i_TSTIN=2**20-1,
|
||||||
|
i_GTREFCLK0=refclk,
|
||||||
|
|
||||||
|
# TX clock
|
||||||
|
p_TXBUF_EN="FALSE",
|
||||||
|
p_TX_XCLK_SEL="TXUSR",
|
||||||
|
o_TXOUTCLK=self.txoutclk,
|
||||||
|
i_TXSYSCLKSEL=0b00,
|
||||||
|
i_TXOUTCLKSEL=0b11,
|
||||||
|
|
||||||
|
# TX Startup/Reset
|
||||||
|
i_TXPHDLYRESET=0,
|
||||||
|
i_TXDLYBYPASS=0,
|
||||||
|
i_TXPHALIGNEN=1 if tx_mode != "single" else 0,
|
||||||
|
i_GTTXRESET=tx_init.gtXxreset,
|
||||||
|
o_TXRESETDONE=tx_init.Xxresetdone,
|
||||||
|
i_TXDLYSRESET=tx_init.Xxdlysreset,
|
||||||
|
o_TXDLYSRESETDONE=tx_init.Xxdlysresetdone,
|
||||||
|
i_TXPHINIT=tx_init.txphinit if tx_mode != "single" else 0,
|
||||||
|
o_TXPHINITDONE=tx_init.txphinitdone if tx_mode != "single" else Signal(),
|
||||||
|
i_TXPHALIGN=tx_init.Xxphalign if tx_mode != "single" else 0,
|
||||||
|
i_TXDLYEN=tx_init.Xxdlyen if tx_mode != "single" else 0,
|
||||||
|
o_TXPHALIGNDONE=tx_init.Xxphaligndone,
|
||||||
|
i_TXUSERRDY=tx_init.Xxuserrdy,
|
||||||
|
p_TXPMARESET_TIME=1,
|
||||||
|
p_TXPCSRESET_TIME=1,
|
||||||
|
i_TXINHIBIT=~self.txenable,
|
||||||
|
|
||||||
|
# TX data
|
||||||
|
p_TX_DATA_WIDTH=20,
|
||||||
|
p_TX_INT_DATAWIDTH=0,
|
||||||
|
i_TXCHARDISPMODE=Cat(txdata[9], txdata[19]),
|
||||||
|
i_TXCHARDISPVAL=Cat(txdata[8], txdata[18]),
|
||||||
|
i_TXDATA=Cat(txdata[:8], txdata[10:18]),
|
||||||
|
i_TXUSRCLK=ClockSignal("rtio_tx"),
|
||||||
|
i_TXUSRCLK2=ClockSignal("rtio_tx"),
|
||||||
|
|
||||||
|
# TX electrical
|
||||||
|
i_TXBUFDIFFCTRL=0b100,
|
||||||
|
i_TXDIFFCTRL=0b1000,
|
||||||
|
|
||||||
|
# RX Startup/Reset
|
||||||
|
i_RXPHDLYRESET=0,
|
||||||
|
i_RXDLYBYPASS=0,
|
||||||
|
i_RXPHALIGNEN=1 if rx_mode != "single" else 0,
|
||||||
|
i_GTRXRESET=rx_init.gtXxreset,
|
||||||
|
o_RXRESETDONE=rx_init.Xxresetdone,
|
||||||
|
i_RXDLYSRESET=rx_init.Xxdlysreset,
|
||||||
|
o_RXDLYSRESETDONE=rx_init.Xxdlysresetdone,
|
||||||
|
i_RXPHALIGN=rx_init.Xxphalign if rx_mode != "single" else 0,
|
||||||
|
i_RXDLYEN=rx_init.Xxdlyen if rx_mode != "single" else 0,
|
||||||
|
o_RXPHALIGNDONE=rx_init.Xxphaligndone,
|
||||||
|
i_RXUSERRDY=rx_init.Xxuserrdy,
|
||||||
|
p_RXPMARESET_TIME=1,
|
||||||
|
p_RXPCSRESET_TIME=1,
|
||||||
|
|
||||||
|
# RX AFE
|
||||||
|
p_RX_DFE_XYD_CFG=0,
|
||||||
|
p_RX_CM_SEL=0b11, # RX_CM_SEL = 0b11: Common mode is programmable
|
||||||
|
p_RX_CM_TRIM=0b010, # PMA_RSV[4],RX_CM_TRIM[2:0] = 0b1010: Common mode 800mV
|
||||||
|
i_RXDFEXYDEN=1,
|
||||||
|
i_RXDFEXYDHOLD=0,
|
||||||
|
i_RXDFEXYDOVRDEN=0,
|
||||||
|
i_RXLPMEN=0, # RXLPMEN = 0: DFE mode is enabled
|
||||||
|
p_RX_DFE_GAIN_CFG=0x0207EA,
|
||||||
|
p_RX_DFE_VP_CFG=0b00011111100000011,
|
||||||
|
p_RX_DFE_UT_CFG=0b10001000000000000,
|
||||||
|
p_RX_DFE_KL_CFG=0b0000011111110,
|
||||||
|
p_RX_DFE_KL_CFG2=0x3788140A,
|
||||||
|
p_RX_DFE_H2_CFG=0b000110000000,
|
||||||
|
p_RX_DFE_H3_CFG=0b000110000000,
|
||||||
|
p_RX_DFE_H4_CFG=0b00011100000,
|
||||||
|
p_RX_DFE_H5_CFG=0b00011100000,
|
||||||
|
p_RX_DFE_LPM_CFG=0x0904, # RX_DFE_LPM_CFG = 0x0904: linerate <= 6.6Gb/s
|
||||||
|
# = 0x0104: linerate > 6.6Gb/s
|
||||||
|
|
||||||
|
# RX clock
|
||||||
|
i_RXDDIEN=1,
|
||||||
|
i_RXSYSCLKSEL=0b00,
|
||||||
|
i_RXOUTCLKSEL=0b010,
|
||||||
|
o_RXOUTCLK=self.rxoutclk,
|
||||||
|
i_RXUSRCLK=ClockSignal("rtio_rx"),
|
||||||
|
i_RXUSRCLK2=ClockSignal("rtio_rx"),
|
||||||
|
|
||||||
|
# RX Clock Correction Attributes
|
||||||
|
p_CLK_CORRECT_USE="FALSE",
|
||||||
|
p_CLK_COR_SEQ_1_1=0b0100000000,
|
||||||
|
p_CLK_COR_SEQ_2_1=0b0100000000,
|
||||||
|
p_CLK_COR_SEQ_1_ENABLE=0b1111,
|
||||||
|
p_CLK_COR_SEQ_2_ENABLE=0b1111,
|
||||||
|
|
||||||
|
# RX data
|
||||||
|
p_RX_DATA_WIDTH=20,
|
||||||
|
p_RX_INT_DATAWIDTH=0,
|
||||||
|
o_RXDISPERR=Cat(rxdata[9], rxdata[19]),
|
||||||
|
o_RXCHARISK=Cat(rxdata[8], rxdata[18]),
|
||||||
|
o_RXDATA=Cat(rxdata[:8], rxdata[10:18]),
|
||||||
|
|
||||||
|
# RX Byte and Word Alignment Attributes
|
||||||
|
p_ALIGN_COMMA_DOUBLE="FALSE",
|
||||||
|
p_ALIGN_COMMA_ENABLE=0b1111111111,
|
||||||
|
p_ALIGN_COMMA_WORD=1,
|
||||||
|
p_ALIGN_MCOMMA_DET="TRUE",
|
||||||
|
p_ALIGN_MCOMMA_VALUE=0b1010000011,
|
||||||
|
p_ALIGN_PCOMMA_DET="TRUE",
|
||||||
|
p_ALIGN_PCOMMA_VALUE=0b0101111100,
|
||||||
|
p_SHOW_REALIGN_COMMA="FALSE",
|
||||||
|
p_RXSLIDE_AUTO_WAIT=7,
|
||||||
|
p_RXSLIDE_MODE="PCS",
|
||||||
|
p_RX_SIG_VALID_DLY=10,
|
||||||
|
|
||||||
|
# RX 8B/10B Decoder Attributes
|
||||||
|
p_RX_DISPERR_SEQ_MATCH="FALSE",
|
||||||
|
p_DEC_MCOMMA_DETECT="TRUE",
|
||||||
|
p_DEC_PCOMMA_DETECT="TRUE",
|
||||||
|
p_DEC_VALID_COMMA_ONLY="FALSE",
|
||||||
|
|
||||||
|
# RX Buffer Attributes
|
||||||
|
p_RXBUF_ADDR_MODE="FAST",
|
||||||
|
p_RXBUF_EIDLE_HI_CNT=0b1000,
|
||||||
|
p_RXBUF_EIDLE_LO_CNT=0b0000,
|
||||||
|
p_RXBUF_EN="FALSE",
|
||||||
|
p_RX_BUFFER_CFG=0b000000,
|
||||||
|
p_RXBUF_RESET_ON_CB_CHANGE="TRUE",
|
||||||
|
p_RXBUF_RESET_ON_COMMAALIGN="FALSE",
|
||||||
|
p_RXBUF_RESET_ON_EIDLE="FALSE", # RXBUF_RESET_ON_EIDLE = FALSE: OOB is disabled
|
||||||
|
p_RXBUF_RESET_ON_RATE_CHANGE="TRUE",
|
||||||
|
p_RXBUFRESET_TIME=0b00001,
|
||||||
|
p_RXBUF_THRESH_OVFLW=61,
|
||||||
|
p_RXBUF_THRESH_OVRD="FALSE",
|
||||||
|
p_RXBUF_THRESH_UNDFLW=4,
|
||||||
|
p_RXDLY_CFG=0x001F,
|
||||||
|
p_RXDLY_LCFG=0x030,
|
||||||
|
p_RXDLY_TAP_CFG=0x0000,
|
||||||
|
p_RXPH_CFG=0xC00002,
|
||||||
|
p_RXPHDLY_CFG=0x084020,
|
||||||
|
p_RXPH_MONITOR_SEL=0b00000,
|
||||||
|
p_RX_XCLK_SEL="RXUSR",
|
||||||
|
p_RX_DDI_SEL=0b000000,
|
||||||
|
p_RX_DEFER_RESET_BUF_EN="TRUE",
|
||||||
|
|
||||||
|
# CDR Attributes
|
||||||
|
p_RXCDR_CFG=0x03000023FF20400020, # DFE @ <= 6.6Gb/s, scrambled, CDR setting < +/- 200ppm
|
||||||
|
# (See UG476 (v1.12.1), p.206)
|
||||||
|
p_RXCDR_FR_RESET_ON_EIDLE=0b0,
|
||||||
|
p_RXCDR_HOLD_DURING_EIDLE=0b0,
|
||||||
|
p_RXCDR_PH_RESET_ON_EIDLE=0b0,
|
||||||
|
p_RXCDR_LOCK_CFG=0b010101,
|
||||||
|
|
||||||
|
# Pads
|
||||||
|
i_GTXRXP=rx_pads.p,
|
||||||
|
i_GTXRXN=rx_pads.n,
|
||||||
|
o_GTXTXP=tx_pads.p,
|
||||||
|
o_GTXTXN=tx_pads.n,
|
||||||
|
|
||||||
|
# Other parameters
|
||||||
|
p_PCS_RSVD_ATTR=(
|
||||||
|
(tx_mode != "single") << 1 | # PCS_RSVD_ATTR[1] = 0: TX Single Lane Auto Mode
|
||||||
|
# = 1: TX Manual Mode
|
||||||
|
(rx_mode != "single") << 2 | # [2] = 0: RX Single Lane Auto Mode
|
||||||
|
# = 1: RX Manual Mode
|
||||||
|
0 << 8 # [8] = 0: OOB is disabled
|
||||||
|
),
|
||||||
|
i_RXELECIDLEMODE=0b11, # RXELECIDLEMODE = 0b11: OOB is disabled
|
||||||
|
p_RX_DFE_LPM_HOLD_DURING_EIDLE=0b0,
|
||||||
|
p_ES_EYE_SCAN_EN="TRUE", # Must be TRUE for GTX
|
||||||
|
)
|
||||||
|
|
||||||
|
# TX clocking
|
||||||
|
tx_reset_deglitched = Signal()
|
||||||
|
tx_reset_deglitched.attr.add("no_retiming")
|
||||||
|
self.sync += tx_reset_deglitched.eq(~tx_init.done)
|
||||||
|
self.clock_domains.cd_rtio_tx = ClockDomain()
|
||||||
|
if tx_mode == "single" or tx_mode == "master":
|
||||||
|
self.specials += Instance("BUFG", i_I=self.txoutclk, o_O=self.cd_rtio_tx.clk)
|
||||||
|
self.specials += AsyncResetSynchronizer(self.cd_rtio_tx, tx_reset_deglitched)
|
||||||
|
|
||||||
|
# RX clocking
|
||||||
|
rx_reset_deglitched = Signal()
|
||||||
|
rx_reset_deglitched.attr.add("no_retiming")
|
||||||
|
self.sync.rtio += rx_reset_deglitched.eq(~rx_init.done)
|
||||||
|
self.clock_domains.cd_rtio_rx = ClockDomain()
|
||||||
|
if rx_mode == "single" or rx_mode == "master":
|
||||||
|
self.specials += Instance("BUFG", i_I=self.rxoutclk, o_O=self.cd_rtio_rx.clk),
|
||||||
|
self.specials += AsyncResetSynchronizer(self.cd_rtio_rx, rx_reset_deglitched)
|
||||||
|
|
||||||
|
self.comb += [
|
||||||
|
txdata.eq(Cat(self.encoder.output[0], self.encoder.output[1])),
|
||||||
|
self.decoders[0].input.eq(rxdata[:10]),
|
||||||
|
self.decoders[1].input.eq(rxdata[10:])
|
||||||
|
]
|
||||||
|
|
||||||
|
clock_aligner = BruteforceClockAligner(0b0101111100, rtio_clk_freq)
|
||||||
|
self.submodules += clock_aligner
|
||||||
|
self.comb += [
|
||||||
|
clock_aligner.rxdata.eq(rxdata),
|
||||||
|
rx_init.restart.eq(clock_aligner.restart),
|
||||||
|
self.rx_ready.eq(clock_aligner.ready)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class GTX(Module, TransceiverInterface):
|
||||||
|
def __init__(self, clock_pads, tx_pads, rx_pads, sys_clk_freq, rtio_clk_freq=125e6, master=0):
|
||||||
|
assert len(tx_pads) == len(rx_pads)
|
||||||
|
self.nchannels = nchannels = len(tx_pads)
|
||||||
|
self.gtxs = []
|
||||||
|
self.rtio_clk_freq = rtio_clk_freq
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
refclk = Signal()
|
||||||
|
stable_clkin_n = Signal()
|
||||||
|
self.specials += Instance("IBUFDS_GTE2",
|
||||||
|
i_CEB=stable_clkin_n,
|
||||||
|
i_I=clock_pads.p,
|
||||||
|
i_IB=clock_pads.n,
|
||||||
|
o_O=refclk
|
||||||
|
)
|
||||||
|
|
||||||
|
rtio_tx_clk = Signal()
|
||||||
|
channel_interfaces = []
|
||||||
|
for i in range(nchannels):
|
||||||
|
if nchannels == 1:
|
||||||
|
mode = "single"
|
||||||
|
else:
|
||||||
|
mode = "master" if i == master else "slave"
|
||||||
|
# Note: RX phase alignment is to be done on individual lanes, not multi-lane.
|
||||||
|
gtx = GTX_20X(refclk, tx_pads[i], rx_pads[i], sys_clk_freq, rtio_clk_freq=rtio_clk_freq, tx_mode=mode, rx_mode="single")
|
||||||
|
# Fan-out (to slave) / Fan-in (from master) of the TXUSRCLK
|
||||||
|
if mode == "slave":
|
||||||
|
self.comb += gtx.cd_rtio_tx.clk.eq(rtio_tx_clk)
|
||||||
|
else:
|
||||||
|
self.comb += rtio_tx_clk.eq(gtx.cd_rtio_tx.clk)
|
||||||
|
self.gtxs.append(gtx)
|
||||||
|
setattr(self.submodules, "gtx"+str(i), gtx)
|
||||||
|
channel_interface = ChannelInterface(gtx.encoder, gtx.decoders)
|
||||||
|
self.comb += channel_interface.rx_ready.eq(gtx.rx_ready)
|
||||||
|
channel_interfaces.append(channel_interface)
|
||||||
|
|
||||||
|
self.submodules.tx_phase_alignment = GTXInitPhaseAlignment([gtx.tx_init for gtx in self.gtxs])
|
||||||
|
|
||||||
|
TransceiverInterface.__init__(self, channel_interfaces)
|
||||||
|
for n, gtx in enumerate(self.gtxs):
|
||||||
|
self.comb += [
|
||||||
|
stable_clkin_n.eq(~self.stable_clkin.storage),
|
||||||
|
gtx.txenable.eq(self.txenable.storage[n])
|
||||||
|
]
|
||||||
|
|
||||||
|
# Connect master's `rtio_tx` clock to `rtio` clock
|
||||||
|
self.comb += [
|
||||||
|
self.cd_rtio.clk.eq(self.gtxs[master].cd_rtio_tx.clk),
|
||||||
|
self.cd_rtio.rst.eq(reduce(or_, [gtx.cd_rtio_tx.rst for gtx in self.gtxs]))
|
||||||
|
]
|
||||||
|
# Connect slave i's `rtio_rx` clock to `rtio_rxi` clock
|
||||||
|
for i in range(nchannels):
|
||||||
|
self.comb += [
|
||||||
|
getattr(self, "cd_rtio_rx" + str(i)).clk.eq(self.gtxs[i].cd_rtio_rx.clk),
|
||||||
|
getattr(self, "cd_rtio_rx" + str(i)).rst.eq(self.gtxs[i].cd_rtio_rx.rst)
|
||||||
|
]
|
|
@ -0,0 +1,250 @@
|
||||||
|
from math import ceil
|
||||||
|
|
||||||
|
from migen import *
|
||||||
|
from migen.genlib.cdc import MultiReg
|
||||||
|
from migen.genlib.misc import WaitTimer
|
||||||
|
from migen.genlib.fsm import FSM
|
||||||
|
|
||||||
|
|
||||||
|
class GTXInit(Module):
|
||||||
|
# Based on LiteSATA by Enjoy-Digital
|
||||||
|
# Choose between Auto Mode and Manual Mode for TX/RX phase alignment with buffer bypassed:
|
||||||
|
# * Auto Mode: When only single lane is involved, as suggested by Xilinx (AR59612)
|
||||||
|
# * Manual Mode: When only multi-lane is involved, as suggested by Xilinx (AR59612)
|
||||||
|
def __init__(self, sys_clk_freq, rx, mode="single"):
|
||||||
|
assert isinstance(rx, bool)
|
||||||
|
assert mode in ["single", "master", "slave"]
|
||||||
|
self.mode = mode
|
||||||
|
|
||||||
|
self.done = Signal()
|
||||||
|
self.restart = Signal()
|
||||||
|
|
||||||
|
# GTX signals
|
||||||
|
self.cplllock = Signal()
|
||||||
|
self.cpllreset = Signal()
|
||||||
|
self.gtXxreset = Signal()
|
||||||
|
self.Xxresetdone = Signal()
|
||||||
|
self.Xxdlysreset = Signal()
|
||||||
|
self.Xxdlysresetdone = Signal()
|
||||||
|
self.Xxphaligndone = Signal()
|
||||||
|
self.Xxuserrdy = Signal()
|
||||||
|
# GTX signals exclusive to multi-lane
|
||||||
|
if mode != "single":
|
||||||
|
self.Xxphalign = Signal()
|
||||||
|
self.Xxdlyen = Signal()
|
||||||
|
# TX only:
|
||||||
|
if not rx:
|
||||||
|
self.txphinit = Signal()
|
||||||
|
self.txphinitdone = Signal()
|
||||||
|
|
||||||
|
# Strobe from master channel to initialize TX/RX phase alignment on slaves
|
||||||
|
self.master_phaligndone = Signal()
|
||||||
|
# Strobe from slave channels to re-enable TX/RX delay alignment on master;
|
||||||
|
# To be combinatorially AND-ed from all slave's `done`
|
||||||
|
if mode == "master":
|
||||||
|
self.slaves_phaligndone = Signal()
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
# Double-latch transceiver asynch outputs
|
||||||
|
cplllock = Signal()
|
||||||
|
Xxresetdone = Signal()
|
||||||
|
Xxdlysresetdone = Signal()
|
||||||
|
Xxphaligndone = Signal()
|
||||||
|
self.specials += [
|
||||||
|
MultiReg(self.cplllock, cplllock),
|
||||||
|
MultiReg(self.Xxresetdone, Xxresetdone),
|
||||||
|
MultiReg(self.Xxdlysresetdone, Xxdlysresetdone),
|
||||||
|
MultiReg(self.Xxphaligndone, Xxphaligndone),
|
||||||
|
]
|
||||||
|
if mode != "single":
|
||||||
|
txphinitdone = Signal()
|
||||||
|
self.specials += MultiReg(self.txphinitdone, txphinitdone)
|
||||||
|
|
||||||
|
# Deglitch FSM outputs driving transceiver asynch inputs
|
||||||
|
gtXxreset = Signal()
|
||||||
|
Xxdlysreset = Signal()
|
||||||
|
Xxuserrdy = Signal()
|
||||||
|
self.sync += [
|
||||||
|
self.gtXxreset.eq(gtXxreset),
|
||||||
|
self.Xxdlysreset.eq(Xxdlysreset),
|
||||||
|
self.Xxuserrdy.eq(Xxuserrdy)
|
||||||
|
]
|
||||||
|
if mode != "single":
|
||||||
|
Xxphalign = Signal()
|
||||||
|
Xxdlyen = Signal()
|
||||||
|
self.sync += [
|
||||||
|
self.Xxphalign.eq(Xxphalign),
|
||||||
|
self.Xxdlyen.eq(Xxdlyen)
|
||||||
|
]
|
||||||
|
if not rx:
|
||||||
|
txphinit = Signal()
|
||||||
|
self.sync += self.txphinit.eq(txphinit)
|
||||||
|
|
||||||
|
# After configuration, transceiver resets have to stay low for
|
||||||
|
# at least 500ns (see AR43482)
|
||||||
|
startup_cycles = ceil(500*sys_clk_freq/1000000000)
|
||||||
|
startup_timer = WaitTimer(startup_cycles)
|
||||||
|
self.submodules += startup_timer
|
||||||
|
|
||||||
|
# PLL reset should be 1 period of refclk
|
||||||
|
# (i.e. 1/(125MHz) for the case of RTIO @ 125MHz)
|
||||||
|
pll_reset_cycles = ceil(sys_clk_freq/125e6)
|
||||||
|
pll_reset_timer = WaitTimer(pll_reset_cycles)
|
||||||
|
self.submodules += pll_reset_timer
|
||||||
|
|
||||||
|
startup_fsm = FSM(reset_state="INITIAL")
|
||||||
|
self.submodules += startup_fsm
|
||||||
|
|
||||||
|
if rx:
|
||||||
|
cdr_stable_timer = WaitTimer(1024)
|
||||||
|
self.submodules += cdr_stable_timer
|
||||||
|
|
||||||
|
# Rising edge detection for phase alignment "done"
|
||||||
|
Xxphaligndone_r = Signal(reset=1)
|
||||||
|
Xxphaligndone_rising = Signal()
|
||||||
|
self.sync += Xxphaligndone_r.eq(Xxphaligndone)
|
||||||
|
self.comb += Xxphaligndone_rising.eq(Xxphaligndone & ~Xxphaligndone_r)
|
||||||
|
|
||||||
|
startup_fsm.act("INITIAL",
|
||||||
|
startup_timer.wait.eq(1),
|
||||||
|
If(startup_timer.done, NextState("RESET_ALL"))
|
||||||
|
)
|
||||||
|
startup_fsm.act("RESET_ALL",
|
||||||
|
gtXxreset.eq(1),
|
||||||
|
self.cpllreset.eq(1),
|
||||||
|
pll_reset_timer.wait.eq(1),
|
||||||
|
If(pll_reset_timer.done, NextState("RELEASE_PLL_RESET"))
|
||||||
|
)
|
||||||
|
startup_fsm.act("RELEASE_PLL_RESET",
|
||||||
|
gtXxreset.eq(1),
|
||||||
|
If(cplllock, NextState("RELEASE_GTH_RESET"))
|
||||||
|
)
|
||||||
|
# Release GTX reset and wait for GTX resetdone
|
||||||
|
# (from UG476, GTX is reset on falling edge
|
||||||
|
# of gttxreset)
|
||||||
|
if rx:
|
||||||
|
startup_fsm.act("RELEASE_GTH_RESET",
|
||||||
|
Xxuserrdy.eq(1),
|
||||||
|
cdr_stable_timer.wait.eq(1),
|
||||||
|
If(Xxresetdone & cdr_stable_timer.done, NextState("DELAY_ALIGN"))
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
startup_fsm.act("RELEASE_GTH_RESET",
|
||||||
|
Xxuserrdy.eq(1),
|
||||||
|
If(Xxresetdone, NextState("DELAY_ALIGN"))
|
||||||
|
)
|
||||||
|
|
||||||
|
# States exclusive to Auto Mode:
|
||||||
|
if mode == "single":
|
||||||
|
# Start delay alignment (pulse)
|
||||||
|
startup_fsm.act("DELAY_ALIGN",
|
||||||
|
Xxuserrdy.eq(1),
|
||||||
|
Xxdlysreset.eq(1),
|
||||||
|
NextState("WAIT_DELAY_ALIGN")
|
||||||
|
)
|
||||||
|
# Wait for delay alignment
|
||||||
|
startup_fsm.act("WAIT_DELAY_ALIGN",
|
||||||
|
Xxuserrdy.eq(1),
|
||||||
|
If(Xxdlysresetdone, NextState("WAIT_FIRST_PHASE_ALIGN_DONE"))
|
||||||
|
)
|
||||||
|
# Wait 2 rising edges of rxphaligndone
|
||||||
|
# (from UG476 in buffer bypass config)
|
||||||
|
startup_fsm.act("WAIT_FIRST_PHASE_ALIGN_DONE",
|
||||||
|
Xxuserrdy.eq(1),
|
||||||
|
If(Xxphaligndone_rising, NextState("WAIT_SECOND_PHASE_ALIGN_DONE"))
|
||||||
|
)
|
||||||
|
startup_fsm.act("WAIT_SECOND_PHASE_ALIGN_DONE",
|
||||||
|
Xxuserrdy.eq(1),
|
||||||
|
If(Xxphaligndone_rising, NextState("READY"))
|
||||||
|
)
|
||||||
|
|
||||||
|
# States exclusive to Manual Mode:
|
||||||
|
else:
|
||||||
|
# Start delay alignment (hold)
|
||||||
|
startup_fsm.act("DELAY_ALIGN",
|
||||||
|
Xxuserrdy.eq(1),
|
||||||
|
Xxdlysreset.eq(1),
|
||||||
|
If(Xxdlysresetdone,
|
||||||
|
# TX master: proceed to initialize phase alignment manually
|
||||||
|
(NextState("PHASE_ALIGN_INIT") if not rx else
|
||||||
|
# RX master: proceed to start phase alignment manually
|
||||||
|
NextState("PHASE_ALIGN")) if mode == "master" else
|
||||||
|
# TX/RX slave: wait for phase alignment "done" on master
|
||||||
|
NextState("WAIT_MASTER")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if mode == "slave":
|
||||||
|
# TX slave: Wait for phase alignment "done" on master
|
||||||
|
startup_fsm.act("WAIT_MASTER",
|
||||||
|
Xxuserrdy.eq(1),
|
||||||
|
If(self.master_phaligndone,
|
||||||
|
# TX slave: proceed to initialize phase alignment manually
|
||||||
|
NextState("PHASE_ALIGN_INIT") if not rx else
|
||||||
|
# RX slave: proceed to start phase alignment manually
|
||||||
|
NextState("PHASE_ALIGN")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if not rx:
|
||||||
|
# TX master/slave: Initialize phase alignment, wait rising edge on "done"
|
||||||
|
startup_fsm.act("PHASE_ALIGN_INIT",
|
||||||
|
Xxuserrdy.eq(1),
|
||||||
|
txphinit.eq(1),
|
||||||
|
If(txphinitdone, NextState("PHASE_ALIGN"))
|
||||||
|
)
|
||||||
|
# Do phase ealignment, wait rising edge on "done"
|
||||||
|
startup_fsm.act("PHASE_ALIGN",
|
||||||
|
Xxuserrdy.eq(1),
|
||||||
|
Xxphalign.eq(1),
|
||||||
|
If(Xxphaligndone_rising,
|
||||||
|
# TX/RX master: proceed to set T/RXDLYEN
|
||||||
|
NextState("FIRST_DLYEN") if mode == "master" else
|
||||||
|
# TX/RX slave: proceed to signal master
|
||||||
|
NextState("READY")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if mode == "master":
|
||||||
|
# Enable delay alignment in manual mode, wait rising edge on phase alignment "done"
|
||||||
|
startup_fsm.act("FIRST_DLYEN",
|
||||||
|
Xxuserrdy.eq(1),
|
||||||
|
Xxdlyen.eq(1),
|
||||||
|
If(Xxphaligndone_rising, NextState("WAIT_SLAVES"))
|
||||||
|
)
|
||||||
|
# Wait for phase alignment "done" on all slaves
|
||||||
|
startup_fsm.act("WAIT_SLAVES",
|
||||||
|
Xxuserrdy.eq(1),
|
||||||
|
self.master_phaligndone.eq(1),
|
||||||
|
If(self.slaves_phaligndone, NextState("SECOND_DLYEN"))
|
||||||
|
)
|
||||||
|
# Re-enable delay alignment in manual mode, wait rising edge on phase alignment "done"
|
||||||
|
startup_fsm.act("SECOND_DLYEN",
|
||||||
|
Xxuserrdy.eq(1),
|
||||||
|
Xxdlyen.eq(1),
|
||||||
|
If(Xxphaligndone_rising, NextState("READY"))
|
||||||
|
)
|
||||||
|
|
||||||
|
# Transceiver is ready, alignment can be restarted
|
||||||
|
startup_fsm.act("READY",
|
||||||
|
Xxuserrdy.eq(1),
|
||||||
|
self.done.eq(1),
|
||||||
|
If(self.restart, NextState("RESET_ALL"))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class GTXInitPhaseAlignment(Module):
|
||||||
|
# Interconnect of phase alignment "done" signals for Manual Mode multi-lane
|
||||||
|
def __init__(self, gtx_inits):
|
||||||
|
master_phaligndone = Signal() # Fan-out to `slave.master_phaligndone`s
|
||||||
|
slaves_phaligndone = Signal(reset=1) # ANDed from `slave.done`s
|
||||||
|
# Slave channels
|
||||||
|
for gtx_init in gtx_inits:
|
||||||
|
if gtx_init.mode == "slave":
|
||||||
|
self.comb += gtx_init.master_phaligndone.eq(master_phaligndone)
|
||||||
|
slaves_phaligndone = slaves_phaligndone & gtx_init.done
|
||||||
|
# Master channels
|
||||||
|
for gtx_init in gtx_inits:
|
||||||
|
if gtx_init.mode == "master":
|
||||||
|
self.comb += [
|
||||||
|
master_phaligndone.eq(gtx_init.master_phaligndone),
|
||||||
|
gtx_init.slaves_phaligndone.eq(slaves_phaligndone)
|
||||||
|
]
|
|
@ -0,0 +1,180 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
from migen import *
|
||||||
|
from migen.build.generic_platform import *
|
||||||
|
from migen.build.xilinx.vivado import XilinxVivadoToolchain
|
||||||
|
from migen.build.xilinx.ise import XilinxISEToolchain
|
||||||
|
|
||||||
|
from misoc.cores import spi as spi_csr
|
||||||
|
from misoc.cores import gpio
|
||||||
|
from misoc.integration.builder import *
|
||||||
|
from misoc.targets.kc705 import MiniSoC, soc_kc705_args, soc_kc705_argdict
|
||||||
|
|
||||||
|
from artiq.gateware.amp import AMPSoC
|
||||||
|
from artiq.gateware import rtio
|
||||||
|
from artiq.gateware.rtio.phy import ttl_simple
|
||||||
|
from artiq.gateware.drtio.transceiver import gtx_7series
|
||||||
|
from artiq.gateware.drtio import *
|
||||||
|
from artiq.build_soc import *
|
||||||
|
|
||||||
|
|
||||||
|
class Master(MiniSoC, AMPSoC):
|
||||||
|
mem_map = {
|
||||||
|
"cri_con": 0x10000000,
|
||||||
|
"rtio": 0x20000000,
|
||||||
|
"rtio_dma": 0x30000000,
|
||||||
|
"drtioaux": 0x50000000,
|
||||||
|
"mailbox": 0x70000000
|
||||||
|
}
|
||||||
|
mem_map.update(MiniSoC.mem_map)
|
||||||
|
|
||||||
|
def __init__(self, gateware_identifier_str=None, **kwargs):
|
||||||
|
MiniSoC.__init__(self,
|
||||||
|
cpu_type="or1k",
|
||||||
|
sdram_controller_type="minicon",
|
||||||
|
l2_size=128*1024,
|
||||||
|
integrated_sram_size=8192,
|
||||||
|
ethmac_nrxslots=4,
|
||||||
|
ethmac_ntxslots=4,
|
||||||
|
**kwargs)
|
||||||
|
AMPSoC.__init__(self)
|
||||||
|
add_identifier(self, gateware_identifier_str=gateware_identifier_str)
|
||||||
|
|
||||||
|
if isinstance(self.platform.toolchain, XilinxVivadoToolchain):
|
||||||
|
self.platform.toolchain.bitstream_commands.extend([
|
||||||
|
"set_property BITSTREAM.GENERAL.COMPRESS True [current_design]",
|
||||||
|
])
|
||||||
|
if isinstance(self.platform.toolchain, XilinxISEToolchain):
|
||||||
|
self.platform.toolchain.bitgen_opt += " -g compress"
|
||||||
|
|
||||||
|
platform = self.platform
|
||||||
|
|
||||||
|
self.comb += platform.request("sfp_tx_disable_n").eq(1)
|
||||||
|
tx_pads = [
|
||||||
|
platform.request("sfp_tx"), platform.request("user_sma_mgt_tx")
|
||||||
|
]
|
||||||
|
rx_pads = [
|
||||||
|
platform.request("sfp_rx"), platform.request("user_sma_mgt_rx")
|
||||||
|
]
|
||||||
|
|
||||||
|
# 1000BASE_BX10 Ethernet compatible, 125MHz RTIO clock
|
||||||
|
self.submodules.drtio_transceiver = gtx_7series.GTX(
|
||||||
|
clock_pads=platform.request("si5324_clkout"),
|
||||||
|
tx_pads=tx_pads,
|
||||||
|
rx_pads=rx_pads,
|
||||||
|
sys_clk_freq=self.clk_freq)
|
||||||
|
self.csr_devices.append("drtio_transceiver")
|
||||||
|
|
||||||
|
self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3)
|
||||||
|
|
||||||
|
drtio_csr_group = []
|
||||||
|
drtioaux_csr_group = []
|
||||||
|
drtioaux_memory_group = []
|
||||||
|
drtio_cri = []
|
||||||
|
for i in range(len(self.drtio_transceiver.channels)):
|
||||||
|
core_name = "drtio" + str(i)
|
||||||
|
coreaux_name = "drtioaux" + str(i)
|
||||||
|
memory_name = "drtioaux" + str(i) + "_mem"
|
||||||
|
drtio_csr_group.append(core_name)
|
||||||
|
drtioaux_csr_group.append(coreaux_name)
|
||||||
|
drtioaux_memory_group.append(memory_name)
|
||||||
|
|
||||||
|
cdr = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)})
|
||||||
|
|
||||||
|
core = cdr(DRTIOMaster(
|
||||||
|
self.rtio_tsc, self.drtio_transceiver.channels[i]))
|
||||||
|
setattr(self.submodules, core_name, core)
|
||||||
|
drtio_cri.append(core.cri)
|
||||||
|
self.csr_devices.append(core_name)
|
||||||
|
|
||||||
|
coreaux = cdr(DRTIOAuxController(core.link_layer))
|
||||||
|
setattr(self.submodules, coreaux_name, coreaux)
|
||||||
|
self.csr_devices.append(coreaux_name)
|
||||||
|
|
||||||
|
memory_address = self.mem_map["drtioaux"] + 0x800*i
|
||||||
|
self.add_wb_slave(memory_address, 0x800,
|
||||||
|
coreaux.bus)
|
||||||
|
self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800)
|
||||||
|
self.config["HAS_DRTIO"] = None
|
||||||
|
self.config["HAS_DRTIO_ROUTING"] = None
|
||||||
|
self.add_csr_group("drtio", drtio_csr_group)
|
||||||
|
self.add_csr_group("drtioaux", drtioaux_csr_group)
|
||||||
|
self.add_memory_group("drtioaux_mem", drtioaux_memory_group)
|
||||||
|
|
||||||
|
self.config["RTIO_FREQUENCY"] = str(self.drtio_transceiver.rtio_clk_freq/1e6)
|
||||||
|
self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n)
|
||||||
|
self.csr_devices.append("si5324_rst_n")
|
||||||
|
i2c = self.platform.request("i2c")
|
||||||
|
self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda])
|
||||||
|
self.csr_devices.append("i2c")
|
||||||
|
self.config["I2C_BUS_COUNT"] = 1
|
||||||
|
self.config["HAS_SI5324"] = None
|
||||||
|
self.config["SI5324_AS_SYNTHESIZER"] = None
|
||||||
|
|
||||||
|
self.comb += [
|
||||||
|
platform.request("user_sma_clock_p").eq(ClockSignal("rtio_rx0")),
|
||||||
|
platform.request("user_sma_clock_n").eq(ClockSignal("rtio"))
|
||||||
|
]
|
||||||
|
|
||||||
|
rtio_clk_period = 1e9/self.drtio_transceiver.rtio_clk_freq
|
||||||
|
# Constrain TX & RX timing for the first transceiver channel
|
||||||
|
# (First channel acts as master for phase alignment for all channels' TX)
|
||||||
|
gtx0 = self.drtio_transceiver.gtxs[0]
|
||||||
|
platform.add_period_constraint(gtx0.txoutclk, rtio_clk_period)
|
||||||
|
platform.add_period_constraint(gtx0.rxoutclk, rtio_clk_period)
|
||||||
|
platform.add_false_path_constraints(
|
||||||
|
self.crg.cd_sys.clk,
|
||||||
|
gtx0.txoutclk, gtx0.rxoutclk)
|
||||||
|
# Constrain RX timing for the each transceiver channel
|
||||||
|
# (Each channel performs single-lane phase alignment for RX)
|
||||||
|
for gtx in self.drtio_transceiver.gtxs[1:]:
|
||||||
|
platform.add_period_constraint(gtx.rxoutclk, rtio_clk_period)
|
||||||
|
platform.add_false_path_constraints(
|
||||||
|
self.crg.cd_sys.clk, gtx0.txoutclk, gtx.rxoutclk)
|
||||||
|
|
||||||
|
rtio_channels = []
|
||||||
|
for i in range(8):
|
||||||
|
phy = ttl_simple.Output(platform.request("user_led", i))
|
||||||
|
self.submodules += phy
|
||||||
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
|
for sma in "user_sma_gpio_p", "user_sma_gpio_n":
|
||||||
|
phy = ttl_simple.InOut(platform.request(sma))
|
||||||
|
self.submodules += phy
|
||||||
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
|
|
||||||
|
self.submodules.rtio_moninj = rtio.MonInj(rtio_channels)
|
||||||
|
self.csr_devices.append("rtio_moninj")
|
||||||
|
|
||||||
|
self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels)
|
||||||
|
self.csr_devices.append("rtio_core")
|
||||||
|
|
||||||
|
self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc)
|
||||||
|
self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")(
|
||||||
|
rtio.DMA(self.get_native_sdram_if()))
|
||||||
|
self.register_kernel_cpu_csrdevice("rtio")
|
||||||
|
self.register_kernel_cpu_csrdevice("rtio_dma")
|
||||||
|
self.submodules.cri_con = rtio.CRIInterconnectShared(
|
||||||
|
[self.rtio.cri, self.rtio_dma.cri],
|
||||||
|
[self.rtio_core.cri] + drtio_cri,
|
||||||
|
enable_routing=True)
|
||||||
|
self.register_kernel_cpu_csrdevice("cri_con")
|
||||||
|
self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con)
|
||||||
|
self.csr_devices.append("routing_table")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="ARTIQ device binary builder / KC705 DRTIO master")
|
||||||
|
builder_args(parser)
|
||||||
|
soc_kc705_args(parser)
|
||||||
|
parser.set_defaults(output_dir="artiq_kc705/master")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
soc = Master(**soc_kc705_argdict(args))
|
||||||
|
build_artiq_soc(soc, builder_argdict(args))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -0,0 +1,194 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
from migen import *
|
||||||
|
from migen.build.generic_platform import *
|
||||||
|
from migen.build.xilinx.vivado import XilinxVivadoToolchain
|
||||||
|
from migen.build.xilinx.ise import XilinxISEToolchain
|
||||||
|
|
||||||
|
from misoc.cores import spi as spi_csr
|
||||||
|
from misoc.cores import gpio
|
||||||
|
from misoc.integration.builder import *
|
||||||
|
from misoc.targets.kc705 import BaseSoC, soc_kc705_args, soc_kc705_argdict
|
||||||
|
|
||||||
|
from artiq.gateware import rtio
|
||||||
|
from artiq.gateware.rtio.phy import ttl_simple
|
||||||
|
from artiq.gateware.drtio.transceiver import gtx_7series
|
||||||
|
from artiq.gateware.drtio.siphaser import SiPhaser7Series
|
||||||
|
from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer
|
||||||
|
from artiq.gateware.drtio import *
|
||||||
|
from artiq.build_soc import *
|
||||||
|
|
||||||
|
|
||||||
|
class Satellite(BaseSoC):
|
||||||
|
mem_map = {
|
||||||
|
"drtioaux": 0x50000000,
|
||||||
|
}
|
||||||
|
mem_map.update(BaseSoC.mem_map)
|
||||||
|
|
||||||
|
def __init__(self, gateware_identifier_str=None, sma_as_sat=False, **kwargs):
|
||||||
|
BaseSoC.__init__(self,
|
||||||
|
cpu_type="or1k",
|
||||||
|
sdram_controller_type="minicon",
|
||||||
|
l2_size=128*1024,
|
||||||
|
integrated_sram_size=8192,
|
||||||
|
**kwargs)
|
||||||
|
add_identifier(self, gateware_identifier_str=gateware_identifier_str)
|
||||||
|
|
||||||
|
if isinstance(self.platform.toolchain, XilinxVivadoToolchain):
|
||||||
|
self.platform.toolchain.bitstream_commands.extend([
|
||||||
|
"set_property BITSTREAM.GENERAL.COMPRESS True [current_design]",
|
||||||
|
])
|
||||||
|
if isinstance(self.platform.toolchain, XilinxISEToolchain):
|
||||||
|
self.platform.toolchain.bitgen_opt += " -g compress"
|
||||||
|
|
||||||
|
platform = self.platform
|
||||||
|
|
||||||
|
self.comb += platform.request("sfp_tx_disable_n").eq(1)
|
||||||
|
tx_pads = [
|
||||||
|
platform.request("sfp_tx"), platform.request("user_sma_mgt_tx")
|
||||||
|
]
|
||||||
|
rx_pads = [
|
||||||
|
platform.request("sfp_rx"), platform.request("user_sma_mgt_rx")
|
||||||
|
]
|
||||||
|
if sma_as_sat:
|
||||||
|
tx_pads = tx_pads[::-1]
|
||||||
|
rx_pads = rx_pads[::-1]
|
||||||
|
|
||||||
|
# 1000BASE_BX10 Ethernet compatible, 125MHz RTIO clock
|
||||||
|
self.submodules.drtio_transceiver = gtx_7series.GTX(
|
||||||
|
clock_pads=platform.request("si5324_clkout"),
|
||||||
|
tx_pads=tx_pads,
|
||||||
|
rx_pads=rx_pads,
|
||||||
|
sys_clk_freq=self.clk_freq)
|
||||||
|
self.csr_devices.append("drtio_transceiver")
|
||||||
|
|
||||||
|
self.submodules.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3)
|
||||||
|
|
||||||
|
drtioaux_csr_group = []
|
||||||
|
drtioaux_memory_group = []
|
||||||
|
drtiorep_csr_group = []
|
||||||
|
self.drtio_cri = []
|
||||||
|
for i in range(len(self.drtio_transceiver.channels)):
|
||||||
|
coreaux_name = "drtioaux" + str(i)
|
||||||
|
memory_name = "drtioaux" + str(i) + "_mem"
|
||||||
|
drtioaux_csr_group.append(coreaux_name)
|
||||||
|
drtioaux_memory_group.append(memory_name)
|
||||||
|
|
||||||
|
cdr = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)})
|
||||||
|
|
||||||
|
# Satellite
|
||||||
|
if i == 0:
|
||||||
|
self.submodules.rx_synchronizer = cdr(XilinxRXSynchronizer())
|
||||||
|
core = cdr(DRTIOSatellite(
|
||||||
|
self.rtio_tsc, self.drtio_transceiver.channels[0], self.rx_synchronizer))
|
||||||
|
self.submodules.drtiosat = core
|
||||||
|
self.csr_devices.append("drtiosat")
|
||||||
|
# Repeaters
|
||||||
|
else:
|
||||||
|
corerep_name = "drtiorep" + str(i-1)
|
||||||
|
drtiorep_csr_group.append(corerep_name)
|
||||||
|
core = cdr(DRTIORepeater(
|
||||||
|
self.rtio_tsc, self.drtio_transceiver.channels[i]))
|
||||||
|
setattr(self.submodules, corerep_name, core)
|
||||||
|
self.drtio_cri.append(core.cri)
|
||||||
|
self.csr_devices.append(corerep_name)
|
||||||
|
|
||||||
|
coreaux = cdr(DRTIOAuxController(core.link_layer))
|
||||||
|
setattr(self.submodules, coreaux_name, coreaux)
|
||||||
|
self.csr_devices.append(coreaux_name)
|
||||||
|
|
||||||
|
memory_address = self.mem_map["drtioaux"] + 0x800*i
|
||||||
|
self.add_wb_slave(memory_address, 0x800,
|
||||||
|
coreaux.bus)
|
||||||
|
self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800)
|
||||||
|
self.config["HAS_DRTIO"] = None
|
||||||
|
self.config["HAS_DRTIO_ROUTING"] = None
|
||||||
|
self.add_csr_group("drtioaux", drtioaux_csr_group)
|
||||||
|
self.add_memory_group("drtioaux_mem", drtioaux_memory_group)
|
||||||
|
self.add_csr_group("drtiorep", drtiorep_csr_group)
|
||||||
|
|
||||||
|
self.config["RTIO_FREQUENCY"] = str(self.drtio_transceiver.rtio_clk_freq/1e6)
|
||||||
|
# Si5324 Phaser
|
||||||
|
self.submodules.siphaser = SiPhaser7Series(
|
||||||
|
si5324_clkin=platform.request("si5324_clkin"),
|
||||||
|
rx_synchronizer=self.rx_synchronizer,
|
||||||
|
ultrascale=False,
|
||||||
|
rtio_clk_freq=self.drtio_transceiver.rtio_clk_freq)
|
||||||
|
platform.add_false_path_constraints(
|
||||||
|
self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output)
|
||||||
|
self.csr_devices.append("siphaser")
|
||||||
|
self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n)
|
||||||
|
self.csr_devices.append("si5324_rst_n")
|
||||||
|
i2c = self.platform.request("i2c")
|
||||||
|
self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda])
|
||||||
|
self.csr_devices.append("i2c")
|
||||||
|
self.config["I2C_BUS_COUNT"] = 1
|
||||||
|
self.config["HAS_SI5324"] = None
|
||||||
|
|
||||||
|
self.comb += [
|
||||||
|
platform.request("user_sma_clock_p").eq(ClockSignal("rtio_rx0")),
|
||||||
|
platform.request("user_sma_clock_n").eq(ClockSignal("rtio"))
|
||||||
|
]
|
||||||
|
|
||||||
|
rtio_clk_period = 1e9/self.drtio_transceiver.rtio_clk_freq
|
||||||
|
# Constrain TX & RX timing for the first transceiver channel
|
||||||
|
# (First channel acts as master for phase alignment for all channels' TX)
|
||||||
|
gtx0 = self.drtio_transceiver.gtxs[0]
|
||||||
|
platform.add_period_constraint(gtx0.txoutclk, rtio_clk_period)
|
||||||
|
platform.add_period_constraint(gtx0.rxoutclk, rtio_clk_period)
|
||||||
|
platform.add_false_path_constraints(
|
||||||
|
self.crg.cd_sys.clk,
|
||||||
|
gtx0.txoutclk, gtx0.rxoutclk)
|
||||||
|
# Constrain RX timing for the each transceiver channel
|
||||||
|
# (Each channel performs single-lane phase alignment for RX)
|
||||||
|
for gtx in self.drtio_transceiver.gtxs[1:]:
|
||||||
|
platform.add_period_constraint(gtx.rxoutclk, rtio_clk_period)
|
||||||
|
platform.add_false_path_constraints(
|
||||||
|
self.crg.cd_sys.clk, gtx.rxoutclk)
|
||||||
|
|
||||||
|
rtio_channels = []
|
||||||
|
for i in range(8):
|
||||||
|
phy = ttl_simple.Output(platform.request("user_led", i))
|
||||||
|
self.submodules += phy
|
||||||
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
|
for sma in "user_sma_gpio_p", "user_sma_gpio_n":
|
||||||
|
phy = ttl_simple.InOut(platform.request(sma))
|
||||||
|
self.submodules += phy
|
||||||
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
|
|
||||||
|
self.submodules.rtio_moninj = rtio.MonInj(rtio_channels)
|
||||||
|
self.csr_devices.append("rtio_moninj")
|
||||||
|
|
||||||
|
self.submodules.local_io = SyncRTIO(self.rtio_tsc, rtio_channels)
|
||||||
|
self.comb += self.drtiosat.async_errors.eq(self.local_io.async_errors)
|
||||||
|
self.submodules.cri_con = rtio.CRIInterconnectShared(
|
||||||
|
[self.drtiosat.cri],
|
||||||
|
[self.local_io.cri] + self.drtio_cri,
|
||||||
|
mode="sync", enable_routing=True)
|
||||||
|
self.csr_devices.append("cri_con")
|
||||||
|
self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con)
|
||||||
|
self.csr_devices.append("routing_table")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="ARTIQ device binary builder / KC705 DRTIO satellite")
|
||||||
|
builder_args(parser)
|
||||||
|
soc_kc705_args(parser)
|
||||||
|
parser.set_defaults(output_dir="artiq_kc705/satellite")
|
||||||
|
parser.add_argument("--sma", default=False, action="store_true",
|
||||||
|
help="use the SMA connectors (RX: J17, J18, TX: J19, J20) "
|
||||||
|
"as DRTIO satellite channel instead of the SFP")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
argdict = dict()
|
||||||
|
argdict["sma_as_sat"] = args.sma
|
||||||
|
|
||||||
|
soc = Satellite(**soc_kc705_argdict(args), **argdict)
|
||||||
|
build_artiq_soc(soc, builder_argdict(args))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Reference in New Issue