简介:这份资源围绕Xilinx FPGA的SelectIO接口技术展开,对应Vivado中SelectIO Interface Wizard(PG070)官方产品指南,面向已有一定FPGA基础、需要配置高速或异构I/O接口的硬件与逻辑设计人员,用于解决多种电气标准下I/O接口定制与IP核集成的实际问题。资源包为1个PDF文件,大小约1.11MB,内容按IP Facts、概述、产品规格、设计流程步骤、IP核设计与详细示例设计等章节组织,系统覆盖LVCMOS、LVTTL、LVDS、HSTL、SSTL等标准的适用条件,性能与资源占用(LUT、FF、I/O缓冲器)的权衡,端口描述,以及自定义生成、约束、仿真、综合实现各环节的要点,并延伸至时钟缓冲与相位调整、数据路径锁存与位宽匹配等细节。已有1856人学习,适合作为接口协议设计与调试时的案头查询手册,也可用于对照核对配置参数、约束写法与例化信号,减少试错成本。
1. 一根 800 Mbps 的差分线,促使我重新理解 SelectIO 结构
项目做到接口联调那一周,前端一颗图像传感器输出 4 lane LVDS,每 lane 800 Mbps,进 FPGA 后要在片内还原成 16 位并行像素流。最省事的想法是每根线挂一个 IBUF,在 fabric 里用高速时钟去采——仿真一切正常,上板数据全是毛刺。问题不在代码,在于采样点根本没落在数据眼图中间。真正把这条路走通,靠的是把 SelectIO 结构里两件事分开看:时钟怎么进来,数据怎么被串并转换。SelectIO IP 核配置本质上就是替你把 IBUF、IDELAY、ISERDES、OSERDES 和时钟原语这一串器件按参数连好线,省掉手写原语实例的重复劳动。这套方案适合正在做高速接口课设、板级联调或者多 FPGA 互连毕设的人,尤其适合那些已经能跑通流水灯、但一碰源同步接口就卡住的情况。
2. 结构拆解:时钟通路与数据通路为什么必须分开设计
SelectIO 电路在实现上被刻意切成两大块:时钟缓冲与操作、逐引脚的数据通路。这种切法并非随意决定,而是由硬件决定的。因为器件里的 I/O 逻辑(ISERDES、OSERDES、IDDR、ODDR)依赖若干个频率和相位关系固定的时钟,这些时钟必须由专门的时钟原语生成;而数据通路的每一根引脚又各自独立,可以单独选择是否插延时、是否串行化、是否双向。把这两件事混在一张图里画,最后往往连哪根时钟驱动了哪个触发器都说不清楚。
2.1 时钟缓冲与时钟操作:从外部时钟到 I/O 逻辑的驱动链
外部进来的时钟先经过一个差分或单端输入缓冲,然后进入时钟原语。这里有个容易被忽略的分叉:如果设计里没有串行化,时钟通常走 MMCM 之后由clk_out输出到 fabric,fabric 直接拿这个时钟去处理并行数据;一旦开了串行化,I/O 逻辑需要的是一个高速位时钟加一个分频时钟,这时候高速位时钟走 BUFIO 直接进 I/O 列,分频后的时钟由clk_div_out送到 fabric。前者是 I/O 时钟域,后者是 fabric 时钟域,两个域之间的数据交接靠 ISERDES/OSERDES 本身完成,不靠 fabric 里的跨时钟域逻辑。
我一般会先在纸上把这条链画出来:外部差分时钟 → 输入缓冲 → MMCM(倍频到 800 MHz) → BUFIO 出位时钟 → BUFR 出 100 MHz 分频时钟 → 分别送进 ISERDES 的 CLK 和 CLKDIV。这条链画不出来,后面的参数配置基本靠猜。BUFIO 只能驱动同一时钟区域内的 I/O 逻辑,不能进 fabric,这是它的硬性限制;BUFR 可以进 fabric,但驱动能力也要看区域划分。很多“仿真对、上板错”的案例,根子就在这里:时钟从 BUFG 绕了一圈进 I/O,抖动和偏斜把眼图吃没了。
复位信号的层次也属于时钟操作这一块,并且比时钟本身更容易出问题。电路里有四种复位:clk_reset管时钟元件,io_reset管其余所有元件,sync_reset在 IDDR 复位类型设为同步时接进 IDDR,delay_reset是输入延时的同步复位。产品指南里明确写了一条约束:io_reset必须在clk_reset撤销之后若干拍再撤销,8:1 串行化时这个间隔是 16 个 I/O 时钟周期。原因很直白——SERDES 的时钟还没稳就把数据通路放开,内部移位寄存器会停在任意状态。
2.2 逐引脚的数据通路:IDDR/ISERDES、ODDR/OSERDES 与旁路
数据通路是逐引脚实例化的,每个引脚一套,互不干扰。输入侧的顺序是:引脚 → 输入缓冲 → 可选输入延时(IDELAYE2) → 数据串行化(ISERDES,可级联)或 IDDR → 器件侧并行数据。输出侧反过来:器件侧并行数据 → OSERDES 或 ODDR → 可选输出延时 → 输出缓冲 → 引脚。双向通路把两边合起来,再加一个tristate_output控制输出级的三态。
这里的“可选”是关键。SelectIO 结构里每一条路径都能被旁路掉:不开串行化,数据就是纯直通,只经过一个寄存器和缓冲;开了延时但没开动态调节,延时值在生成时就固定下来;开了动态调节,delay_data_ce、delay_data_inc、delay_tap_in、delay_tap_out这几个端口才会暴露出来。这种设计让同一个 IP 既能当最简单的电平转换器用,也能当 16 位 1:8 串行化收发器用。
串并比和位宽的关系要提前算清楚。IP 支持最大 16 位的数据总线,串行化时这 16 位对应的是并行侧宽度,串行侧是 1 位(SDR)或 2 位(DDR)。我见过有人把 16 位并行、8:1 串行化、双沿采样三个条件同时打开,然后疑惑为什么clk_div_in的频率算出来是 100 MHz 而clk_in是 800 MHz——其实就是并行宽度 16 除以串并比 8 得到 2,再乘以 DDR 的 2,分频比是 2,这种组合下并行侧只需要两个 100 MHz 的时钟周期就送完 16 位。把这层关系写进参数表,比事后看波形猜要省事得多。
2.3 端口按功能分组:时钟、复位、引脚侧、器件侧、控制与延时
端口数量看着多,实际按功能分五组就理清了。所有端口都是可选的,实际暴露哪些由你选的参数决定,但至少会有一个输入时钟、一个接引脚的信号、一个接器件侧的信号。
| 分组 | 典型端口 | 关键说明 |
|---|---|---|
| 时钟 | clk_in/clk_in_p/clk_in_n、clk_enable、clk_out、clk_div_in、clk_div_out、ref_clock | 单端或差分二选一;ref_clock供 IDELAYCTRL 使用,必须走 BUFG |
| 复位 | clk_reset、io_reset、sync_reset、delay_reset | io_reset撤销时机比clk_reset晚若干拍 |
| 引脚侧数据 | data_in_from_pins(_p/_n)、data_out_to_pins(_p/_n)、data_to_and_from_pins(_p/_n) | 差分时带_p/_n后缀成对出现 |
| 器件侧数据 | data_in_to_device、data_out_from_device | fabric 侧看到的并行总线 |
| 控制与延时 | bitslip、tristate_output、delay_data_ce、delay_data_inc、delay_tap_in[4:0]、delay_tap_out[4:0]、delay_locked | bitslip宽度随数据宽度变化;延时端口只在开启动态调节时出现 |
bitslip这一组端口值得单独说一句。它只在输入通路上有,并且只在 ISERDES 工作在 NETWORKING 模式下才起作用,宽度n跟数据宽度一致。很多做以太网类网络协议接口的项目,收发器对齐靠的就是这个信号,每次拉高把并行数据窗口挪一位,挪到帧头对上了为止。如果模板选的是普通 chip-to-chip 而不是 NETWORKING 模式,这个端口即使接出来也不会有任何效果,这一点后面避坑章节会再提一次。
delay_locked是 IDELAYCTRL 的输出,它不拉高就说明参考时钟有问题,此时delay_tap_in写进去的值不会真正生效,读回来的delay_tap_out也是无效值。调试延时功能时,第一步永远是看这个信号,而不是去翻抽头值算得对不对。
3. IP 核配置:六步把一个模板落到可综合的 HDL
配置向导里参数有几十个,但真正决定结构走向的只有六步,剩下的都是细节填充。我习惯按“模板 → 电气标准 → 方向与位宽 → 串并比与数率 → 时钟方案 → 延时与控制”这个顺序走,每一步的产物都能在下一步里被验证,不至于配到一半发现前面的前提就不成立。
3.1 先选模板和电气标准,再谈别的
模板是向导里最省时间的东西,它把一组常用参数预先组合好:chip-to-chip、camera receiver、camera transmitter、DVI receiver、DVI transmitter、SGMII。做图像采集,camera receiver 模板基本能覆盖 80% 的需求,它预设了输入方向、串行化、DDR 采样和相应的时钟结构;做以太网类接口用 SGMII 模板,串并比和 bit slip 的默认值已经按协议对齐好了。模板不改变最终生成的电路结构,它只是帮你少点几十下鼠标,但前提是模板选得对——选错了模板再改参数,很容易留下几个不协调的默认值。
电气标准分单端和差分两大类。单端这边有 HSTL 系列(HSTL_I、HSTL_II、HSTL_III 及各自的 1.8 V、1.2 V 版本)、LVCMOS 系列(33/25/18/15/12)、SSTL15、SSTL18_I、SSTL18_II;差分这边有 DIFF_HSTL、DIFF_SSTL15、DIFF_SSTL18_I/II、LVDS25、LVDS、MINI_LVDS_25、PPDS_25、BLVDS_25、RSDS_25、TMDS_33。选标准不是挑“看起来高级”的,而是看你板子上真实的端接和摆幅。LVDS25 配 100 Ω 差分端接,TMDS_33 是 HDMI 类应用的 3.3 V 标准,这两个混用的结果就是输出幅度不够、接收端判不出电平。
3.2 数据宽度、串并比与数据传输方向
数据宽度最大 16 位,这个上限来自器件 I/O 逻辑的并行侧宽度,不是软件限制。选位宽时按实际总线来:8 位并行配 8:1 串行化,串行侧就是单沿 1 位或双沿 2 位;16 位并行配 8:1,并行侧要两个时钟周期送完,分频比相应变成 2 倍关系。
方向有输入、输出、双向三种。双向通路要额外考虑tristate_output的时序——这个信号是与输入数据同步的,不是随便给个使能就行。切换方向时如果三态控制比数据晚一拍,总线上会出现一个短暂的双方同时驱动的窗口,示波器上看就是一个小尖峰,功能上表现为偶发误码。通常的做法是把三态控制的寄存器打一拍到与输出数据同源,别让它跨时钟域。
3.3 时钟方案:BUFIO/BUFR、MMCM 与 IDELAYCTRL 的取舍
时钟原语的选择直接决定端口暴露情况。选 MMCM,不开串行化时clk_out可用;开串行化时clk_div_in可用,用于把分频时钟从外部送进 I/O 逻辑。选 BUFIO,开串行化时clk_div_out可用,分频时钟由 I/O 列内部产生再送到 fabric。
我的取舍原则是:只要 I/O 列里有串行化,位时钟一律走 BUFIO,不要让位时钟绕 BUFG;分频时钟按 fabric 侧要不要用它来决定出口。fabric 需要处理并行数据,就用 BUFR 或 BUFIO 的clk_div_out;fabric 完全不碰并行数据(比如只是直通到另一个 IP),那分频时钟在内部解决就行。
ref_clock是另一条独立的链。它专门给 IDELAYCTRL 用,要求从 BUFG 过来,频率按 200 MHz 量级配置,不能拿位时钟或者分频时钟凑。有些人为了省一个时钟资源,把clk_div_out直接接到ref_clock,短时间可能跑得动,温度一变delay_locked就掉,抽头值漂移,眼图中心跑偏。这个坑一次就够记一辈子。
3.4 延时与 bitslip:可编程抽头怎么留出控制口
延时插入分固定和动态两种。固定延时在生成时把抽头数写死,端口不暴露,适合板级走线已知且不会变的场景。动态延时会暴露delay_data_ce、delay_data_inc、delay_tap_in[4:0]、delay_tap_out[4:0],每个 IODELAYE2 实例一套,用delay_data_ce配合delay_data_inc一个抽头一个抽头地挪,或者用delay_tap_in直接加载目标值。
调试阶段我建议一律开动态。上板后先用delay_tap_in扫一遍 0 到 31,记录每个抽头值下的误码情况,找出误码率为零的那一段窗口,取中点写死。这套流程比在代码里改常量、重新综合、重新下板快一个数量级,而且能直接量化出眼图宽度。窗口只有两三个抽头宽的时候,说明走线或者端接有问题,别指望靠调延时救回来。
3.5 生成产物与例化骨架
向导生成的产物包括 Verilog 设计文件、可综合的 example design、演示用 test bench,以及一个 XDC 约束文件。设计文件里已经把缓冲、延时、SERDES、时钟原语全部实例化好并用参数连好,你的工作就剩下例化和接信号。
// 8 位并行、8:1 串行化、DDR 采样的输入通路例化骨架 // 端口名与向导生成文件保持一致,未启用的端口不要出现在例化里 selectio_wiz_0 u_selectio_rx ( // ---- 时钟 ---- .clk_in_p (rx_clk_p), // 外部差分时钟正端 .clk_in_n (rx_clk_n), // 外部差分时钟负端 .clk_div_in (clk_100m), // 分频时钟,来自 BUFR/MMCM,频率 = 位时钟/8 .ref_clock (clk_200m), // IDELAYCTRL 参考时钟,必须走 BUFG // ---- 复位 ---- .clk_reset (clk_rst), // 先撤销 .io_reset (io_rst), // 在 clk_rst 撤销后延迟 16 个 I/O 时钟周期再撤销 .delay_reset (delay_rst), // 输入延时的同步复位,高有效 // ---- 引脚侧 ---- .data_in_from_pins_p (rx_data_p), // 差分输入正端,位宽 = 1 .data_in_from_pins_n (rx_data_n), // 差分输入负端 // ---- 器件侧 ---- .data_in_to_device (rx_parallel), // 并行数据输出,位宽 = 8 // ---- 控制与延时 ---- .bitslip (rx_bitslip), // 位对齐控制,NETWORKING 模式有效 .delay_data_ce (delay_ce), // 延时调节使能 .delay_data_inc (delay_inc), // 1 加抽头,0 减抽头 .delay_tap_in (delay_tap_in), // 5 位目标抽头值,可直接加载 .delay_tap_out (delay_tap_out), // 5 位当前抽头值,回读监视 .delay_locked (delay_locked) // 未拉高说明 ref_clock 有问题 );这段例化里,clk_div_in和clk_in_p/n的频率关系是整个设计的地基:位时钟 800 MHz、8:1 串行化、DDR 采样,分频时钟就是 800/8×2 关系下的 200 MHz 还是 100 MHz,取决于并行侧一个周期送几位。参数说明里那句“分频比 = 并行宽度 / 串并比 × 数率因子”是唯一需要死记的公式。ref_clock单独一路,不要复用。bitslip的位宽等于并行数据宽度,接错位宽综合能过,行为完全错乱。delay_tap_out在调试阶段一定要引到顶层并接到 ILA 上,否则你不知道延时到底写进去没有。
4. 约束与实现:XDC 写不对,前面全白干
IP 核生成得再正确,引脚和时序约束写错一样上不了板。XDC 这部分的工作量不大,但每一条都影响结果,而且错误的表现形式往往很隐蔽——综合能过、实现能过、时序报告也“通过”,上板就是不通。
4.1 引脚与 I/O 标准约束
引脚分配的第一条铁律是差分对必须落在专用差分对上,P/N 不能反。器件的手册里每个 bank 都标了哪些引脚能组成差分对,向导生成的 XDC 里通常给出了示例格式,照着改成实际引脚号即可。
# 差分输入时钟:必须落在支持差分输入的专用时钟引脚上 set_property PACKAGE_PIN "AE5" [get_ports rx_clk_p] set_property PACKAGE_PIN "AF5" [get_ports rx_clk_n] set_property IOSTANDARD "LVDS25" [get_ports rx_clk_p] set_property IOSTANDARD "LVDS25" [get_ports rx_clk_n] # 差分数据线:每对 P/N 必须是同一差分对,IOSTANDARD 与端接匹配 set_property PACKAGE_PIN "AD4" [get_ports {rx_data_p[0]}] set_property PACKAGE_PIN "AD3" [get_ports {rx_data_n[0]}] set_property IOSTANDARD "LVDS25" [get_ports {rx_data_p[*] rx_data_n[*]}] # 单端控制信号:注意 bank 电压一致 set_property PACKAGE_PIN "AB7" [get_ports delay_locked] set_property IOSTANDARD "LVCMOS18" [get_ports delay_locked]注意IOSTANDARD是整组一起设的,差分组和单端组要分开写,同一个 bank 里混用不同电压标准会直接报错。LVDS25需要外部 100 Ω 端接电阻或者使用内部差分端接原语,具体看器件支持情况。引脚顺序反了(rx_data_p[0]接到 N 端)综合不会报错,功能上表现为这一位恒定或者全错,排查时很费时间,所以分配完引脚后我一般会对着原理图逐对核一遍。
4.2 时钟约束与 IDELAYCTRL 参考时钟
时钟约束要覆盖三件事:输入时钟的周期、生成时钟的关系、输入输出延时。IP 内部的时钟原语会自动派生生成时钟,但输入时钟本身必须手工创建,否则时序分析里这一段是空的,实现工具会按最宽松的方式优化,结果就是把余量吃掉。
# 外部输入时钟:800 MHz 位时钟 create_clock -name rx_clk_in -period 1.250 [get_ports rx_clk_p] # IDELAYCTRL 参考时钟:200 MHz,单独约束,不要复用位时钟 create_clock -name ref_clk_200m -period 5.000 [get_ports clk_200m] # 输入延时:以源同步方式给出,数据相对时钟的到达窗口 set_input_delay -clock rx_clk_in -max 0.350 [get_ports {rx_data_p[*]}] set_input_delay -clock rx_clk_in -min 0.050 [get_ports {rx_data_p[*]}] set_input_delay -clock rx_clk_in -clock_fall -max 0.350 [get_ports {rx_data_p[*]}] -add_delay set_input_delay -clock rx_clk_in -clock_fall -min 0.050 [get_ports {rx_data_p[*]}] -add_delay # 异步控制信号:告诉工具不要按时序路径分析 set_false_path -from [get_ports {delay_tap_in[*] bitslip}]create_clock里的周期按频率倒数写,800 MHz 就是 1.250 ns,写错一个数量级工具不会报错,但所有时序结论都是错的。set_input_delay的-clock_fall那一组在 DDR 采样时必须补上,否则只有正沿被约束,负沿的路径完全没被分析。set_false_path那段是为了避免工具把手工拨动的抽头值当成需要满足建立保持时间的路径去优化,白白浪费时序余量。
4.3 综合与实现阶段的检查项
综合通过不代表什么,关键看实现之后的几个报告。第一条是时序报告里rx_clk_in这一组的 WNS,源同步接口的输入侧通常会有负余量,这是正常的,因为真正的采样点在 IDELAY 后面,工具算不到;但负到 -2 ns 以上就要怀疑约束写错了。第二条是时钟交互报告,确认ref_clock和位时钟之间没有意外的时序路径,有的话要补set_clock_groups -asynchronous。
第三条最容易被跳过:在实现后的网表里确认 IDELAYE2 和 ISERDES 没有被优化掉。有些人写了延时逻辑但没打开动态调节,综合工具发现delay_tap_in是常量,直接把整个延时链优化成直连,时序报告干干净净,功能就是不工作。检查方式是打开综合后的原理图,数一数 IODELAY 实例个数是不是等于引脚数。
5. 避坑与排查:五个最容易翻车的点
5.1 复位释放顺序颠倒,数据永远错位
现象是仿真波形完全正确,上板后并行数据偶尔全零、偶尔错一个固定偏移,重新上电有时候又能好一阵。原因基本锁定在io_reset和clk_reset的释放顺序上:两个复位同时撤销,SERDES 内部移位寄存器在时钟还没稳的时候就被放开,停在任意相位。解决办法是把io_reset的撤销延迟到clk_reset撤销之后 16 个 I/O 时钟周期,用一个计数器实现,别用两个独立的上电复位模块各管各的。
5.2 IDELAYCTRL 参考时钟接错,抽头值形同虚设
现象是delay_tap_in写进去 0 到 31 扫一遍,数据质量毫无变化,delay_locked一直是低。原因是ref_clock没有从 BUFG 走,或者频率偏离 200 MHz 太多,IDELAYCTRL 根本不工作。解决办法是把参考时钟单独引一路,从时钟输入引脚进 BUFG 再进 IP,频率严格按手册给的范围配置,上板先测delay_locked拉高再谈调延时。
5.3 bitslip 当万能钥匙,模式没开就白拨
现象是帧头永远对不上,不停拨bitslip也只是在不同错位之间跳,找不到正确边界。原因是 ISERDES 工作在普通模式而不是 NETWORKING 模式,bitslip端口接出来了但没有实际功能;或者数据宽度和bitslip位宽不一致,一次拨动挪了不止一位。解决办法是回向导里确认串行化模式,需要位对齐的场景必须选 NETWORKING,bitslip宽度严格等于并行数据宽度,并且拨动后要等至少两个并行时钟周期再判断结果。
5.4 差分对引脚分配不合法,编译过了也没数据
现象是综合实现全绿,下载后接收端一个跳变都没有,示波器量引脚是静态电平。原因是 P/N 被分到了不同 bank 或者不是合法的差分对,工具在某些版本下只给警告不报错,约束被静默忽略。解决办法是分配引脚时对照器件的引脚说明,确认每一对都落在专用差分对上,分配完后在实现报告的 I/O 分配表里逐对核对,别只看约束文件写了什么。
5.5 输出时钟用 BUFG 直出,时序余量被悄悄吃光
现象是输出接口的接收端误码率随温度上升而升高,室温下跑几小时才出一次。原因是时钟前传路径走的是 BUFG 而不是 ODDR 直出,时钟和数据从 fabric 出来之后的偏斜不一致,眼图被压窄。解决办法是时钟前传一律用 ODDR 把时钟当数据发出去,保证时钟和数据经过完全相同的路径和相同的延时单元,这样偏斜在两端相互抵消。
6. 验收与答辩:用三张波形和一条回环链路证明它真的通了
验收这件事,最忌讳的是拿“仿真波形对了”当成结论。答辩现场被问一句“你怎么证明上板之后采样点在眼图中间”,只拿仿真截图是答不上来的。我一般的做法是准备三层证据,层层递进。
第一层是配置正确性证据:向导生成的参数摘要截图,加上delay_locked拉高的 ILA 抓图,证明参考时钟链路是活的。
第二层是数据正确性证据:用递增计数器作为测试图案,从器件侧发出去,经过外部回环(或者板内自环)回到输入侧,在 ILA 里对比收发两个计数器。这一段要抓两张图,一张是正常锁定状态,一张是故意拨动bitslip之后的错位状态,两张对比能直接说明位对齐机制是有效的。
第三层是余量证据:把delay_tap_in从 0 扫到 31,每个抽头值下统计一段固定时长的误码数,做成一张表。窗口宽度就是这套接口的实际时序余量。
| 验收项 | 判据 | 观测手段 |
|---|---|---|
| 参考时钟链路 | delay_locked稳定为高,复位后 100 μs 内拉高 | ILA / 示波器 |
| 位对齐 | 拨动bitslip后并行数据按位循环移位,且能回到锁定态 | ILA 对比抓图 |
| 数据通路 | 回环计数器连续 10^9 个周期零错误 | 板级回环 + 误码统计 |
| 延时窗口 | 零误码抽头数不少于 8 个(共 32 个) | 抽头扫描表 |
| 时序收敛 | 输入侧 WNS 解释得清,无未约束路径 | 实现后的时序报告 |
答辩时被追问细节,最有说服力的是那张抽头扫描表。它会暴露真实问题:窗口只有两三个抽头宽,说明端接或者走线有问题;窗口整体偏移到一侧,说明约束里的输入延时给错了。这两件事在仿真里永远看不出来,只有上板扫一遍才知道。
还有个小技巧:把delay_tap_out和一个自由运行的计数器一起接到 ILA,触发条件设成误码出现,这样能抓到出错瞬间的抽头值和数据相位,比事后猜要快得多。我第一次做这类接口时没留这个观测口,出了问题只能一遍遍改代码重综合,一个下午过去连问题出在延时还是复位都没分清。从那以后我每次开这类 IP,都强制把delay_tap_out、delay_locked、bitslip这三个信号引到顶层并挂上 ILA,哪怕最终版本要删掉也先留着。希望这套流程帮到你。
本文还有配套的精品资源,点击获取