赞
踩
通过对时钟和复位的理解可以更好的了解IP核的工作过程,不过不理解也不影响使用,example design帮我们都做好了。
可以直接看总结
PHY在两个时钟域上运行:phy_clk是主要的核心时钟,gt_pcs_clk用于串行收发器接口。gt_clk不被PHY使用,而是被串行收发器接口使用。gt_pcs_clk的频率是gt_clk的一半。一般来说,phy_clk等于 (gt_clk * 操作链路宽度)/4 ,因此,对于配置为2x的核心,phy_clk的频率是gt_clk的一半。如果核心降到1x模式,phy_clk必须切换到gt_clk速率的四分之一。串行收发器还需要一个参考时钟(refclk),使用收发器的专用时钟引脚。参考时钟频率在生成核心时选择(可用选项取决于架构和线速率)。
LOG(逻辑层)在log_clk域上运行。为了达到最佳吞吐量,log_clk应至少与phy_clk一样快。这是为了PHY层接收到的数据不会在BUF里一直停留。
BUF(缓冲器)在log_clk和phy_clk域之间传输数据包。如果BUF用于统一时钟,则log_clk和phy_clk必须同步。否则,时钟必须匹配与接口子核心的速率。
每个子核心配置寄存器接口上的cfg_clk域是独立于该子核心时钟的。但是,为了使用提供的配置结构参考设计中的LOG维护控制器,所有这些接口的cfg_clk必须等同于log_clk。
下表是xilinx给出的典型时钟速率,我们以4x为例进行分析:
下图当中的示例设计采用单个差分输入时钟sys_clk,并实例化所需的时钟缓冲器和时钟模块来生成时钟。时钟方案在不同的FPGA系列之间略有不同,以适应每个设备的特定架构。sys_clk_p和sys_clk_n与DIFF_CLK接口相关联。
MMCM的乘法器和除法器值取决于参考时钟频率和线速率。在4x配置中,log_clk和gt_clk共享一个BUFG。在1x配置中,log_clk和phy_clk共享一个BUFG(并且不需要BUFGMUX,因为只有一个可能的phy_clk速率)。此外,如果在Vivado IDE中选择了统一时钟选项,则要求log_clk和phy_clk具有相同的速率。这意味着log_clk/cfg_clk的BUFG可以被移除,并且log_clk/cfg_clk与phy_clk绑定。
IP核当中有6个时钟输入,简单总结如下:
这是示例工程当中的时钟模块,它将我们需要的时钟全部都已经产生好了,其中输入时钟信号sys_clkp就是GT外部参考时钟,mode_1x表示当前为1Line。
module srio_gen2_0_srio_clk (// Clock in ports input sys_clkp, input sys_clkn, // Status and control signals input sys_rst, input mode_1x, // Clock out ports output log_clk, output phy_clk, output gt_pcs_clk, output gt_clk, output refclk, output drpclk, // Status and control signals output clk_lock ); //------------------------------------ // wire declarations //------------------------------------ wire refclk_bufg; wire clkout0; wire clkout1; wire clkout2; wire clkout3; wire [15:0] do_unused; wire drdy_unused; wire psdone_unused; wire clkfbout; wire to_feedback_in; wire clkfboutb_unused; wire clkout0b_unused; wire clkout1b_unused; wire clkout2b_unused; wire clkout3_unused; wire clkout3b_unused; wire clkout4_unused; wire clkout5_unused; wire clkout6_unused; wire clkfbstopped_unused; wire clkinstopped_unused; // End wire declarations //------------------------------------ // // input buffering //------------------------------------ IBUFDS_GTE2 u_refclk_ibufds( .O (refclk), .I (sys_clkp), .IB (sys_clkn), .CEB (1'b0), .ODIV2 () ); BUFG refclk_bufg_inst (.O (refclk_bufg), .I (refclk)); // End input buffering // MMCME2_ADV instantiation //------------------------------------ MMCME2_ADV #(.BANDWIDTH ("OPTIMIZED"), .CLKOUT4_CASCADE ("FALSE"), .COMPENSATION ("ZHOLD"), .STARTUP_WAIT ("FALSE"), .DIVCLK_DIVIDE (1), .CLKFBOUT_MULT_F (6.000), .CLKFBOUT_PHASE (0.000), .CLKFBOUT_USE_FINE_PS ("FALSE"), .CLKOUT0_DIVIDE_F (3.000), .CLKOUT0_PHASE (0.000), .CLKOUT0_DUTY_CYCLE (0.500), .CLKOUT0_USE_FINE_PS ("FALSE"), .CLKOUT1_DIVIDE (12), .CLKOUT1_PHASE (0.000), .CLKOUT1_DUTY_CYCLE (0.500), .CLKOUT1_USE_FINE_PS ("FALSE"), .CLKOUT2_DIVIDE (6), .CLKOUT2_PHASE (0.000), .CLKOUT2_DUTY_CYCLE (0.500), .CLKOUT2_USE_FINE_PS ("FALSE"), .CLKIN1_PERIOD (6.400), .REF_JITTER1 (0.010)) srio_mmcm_inst // Output clocks (.CLKFBOUT (clkfbout), .CLKFBOUTB (clkfboutb_unused), .CLKOUT0 (clkout0), .CLKOUT0B (clkout0b_unused), .CLKOUT1 (clkout1), .CLKOUT1B (clkout1b_unused), .CLKOUT2 (clkout2), .CLKOUT2B (clkout2b_unused), .CLKOUT3 (clkout3_unused), .CLKOUT3B (clkout3b_unused), .CLKOUT4 (clkout4_unused), .CLKOUT5 (clkout5_unused), .CLKOUT6 (clkout6_unused), // Input clock control .CLKFBIN (clkfbout), .CLKIN1 (refclk_bufg), .CLKIN2 (1'b0), // Tied to always select the primary input clock .CLKINSEL (1'b1), // Ports for dynamic reconfiguration .DADDR (7'h0), .DCLK (1'b0), .DEN (1'b0), .DI (16'h0), .DO (do_unused), .DRDY (drdy_unused), .DWE (1'b0), // Ports for dynamic phase shift .PSCLK (1'b0), .PSEN (1'b0), .PSINCDEC (1'b0), .PSDONE (psdone_unused), // Other control and status signals .LOCKED (clk_lock), .CLKINSTOPPED (clkinstopped_unused), .CLKFBSTOPPED (clkfbstopped_unused), .PWRDWN (1'b0), .RST (1'b0) ); // End 7 series MMCM instantiation //______________________________________________________________________________ // output buffering //----------------------------------- BUFG drpclk_bufr_inst (.O (drpclk), .I (clkout1)); BUFG gt_clk_bufg_inst (.O (gt_clk), .I (clkout0)); BUFG gt_pcs_clk_bufg_inst (.O (gt_pcs_clk), .I (clkout2)); // Note that this bufg is a duplicate of the log_clk bufg, and is not necessary if BUFG resources are limited. BUFG phy_clk_bufg_inst (.O (phy_clk), .I (clkout1)); (* DONT_TOUCH = "true" *) BUFG log_clk_bufg_inst (.O (log_clk), .I (clkout1)); // End output buffering //______________________________________________________________________________ endmodule
每个时钟域都有一个关联的复位信号。复位应该在各自的时钟域中被断言至少四个时钟周期,并且在同步的情况下去除(注意,如果核心被训练降频(比如:一端是4line,对端是1line,那么在建链的时候,速率会被降低到1line),phy_clk运行速度会比原始速率慢,复位仍然必须持续四个完整周期)。
包含的复位参考设计模块(srio_rst.v)有一个单一的复位输入,sys_rst。该信号是一个异步输入。此模块将复位同步到每个时钟域,并扩展脉冲以满足最小复位周期要求。
初始硬件复位应由用户设计生成。复位也可以使用RapidIO协议在带内进行通信。在重置SRIO Gen2 Endpoint 设备时必须特别小心。为了保证ackID对齐,应将所有的链路伙伴一起重置(也就是PHY、BUF、LOG这些模块都要复位)。建议在链路伙伴之间的复位重叠以减少丢失数据包和控制符号的发生。实现此操作的一种方法是进行核心复位的握手。从链路伙伴接收到的复位通过phy_rcvd_link_reset信号从核心传达给用户设计。在接收到链路复位时,应断言sys_rst信号。根据实现方式,可以根据phy_rcvd_link_reset的断言向用户应用程序发送复位信号。要向链路伙伴发送复位请求,请断言phy_link_reset信号,直到port_initialized输出变为低电平。在此时,应断言sys_rst到复位参考设计,完成握手。
个人总结:
上面都是翻译文档的。。。大概意思估计是要复位SRIO Gen2 Endpoint 的时候,先拉高phy_link_reset信号,然后IP核就会断言phy_rcvd_link_reset信号,那么此时用户就应该断言sys_rst有效,然后其他模块(PHY、BUF、LOG)就要跟着一起复位来保证ackID对齐,不过看示例工程里面的代码,不用管sys_rst,这个模块一旦收到phy_rcvd_link_reset信号有效,不需要你断言sys_rst就开始进行复位其他模块了。
以下是示例工程里面的代码:
module srio_gen2_0_srio_rst ( input cfg_clk, // CFG interface clock input log_clk, // LOG interface clock input phy_clk, // PHY interface clock input gt_pcs_clk, // GT Fabric interface clock input sys_rst, // Global reset signal input port_initialized, // Port is intialized input phy_rcvd_link_reset, // Received 4 consecutive reset symbols input force_reinit, // Force reinitialization input clk_lock, // Indicates the MMCM has achieved a stable clock output reg controlled_force_reinit, // Force reinitialization output cfg_rst, // CFG dedicated reset output log_rst, // LOG dedicated reset output buf_rst, // BUF dedicated reset output phy_rst, // PHY dedicated reset output gt_pcs_rst // GT dedicated reset ); // {{{ Parameter declarations ----------- // Reset State Machine localparam IDLE = 4'b0001; localparam LINKRESET = 4'b0010; localparam PHY_RESET1 = 4'b0100; localparam PHY_RESET2 = 4'b1000; // }}} End Parameter declarations ------- wire sys_rst_buffered; // {{{ wire declarations ---------------- reg [0:3] reset_state = IDLE; reg [0:3] reset_next_state = IDLE; (* ASYNC_REG = "TRUE" *) reg [3:0] cfg_rst_srl; (* ASYNC_REG = "TRUE" *) reg [3:0] log_rst_srl; (* ASYNC_REG = "TRUE" *) reg [3:0] phy_rst_srl; (* ASYNC_REG = "TRUE" *) reg [3:0] gt_pcs_rst_srl; reg sys_rst_int; wire reset_condition = sys_rst || phy_rcvd_link_reset || sys_rst_int; // }}} End wire declarations ------------ assign cfg_rst = cfg_rst_srl[3]; always @(posedge cfg_clk or posedge reset_condition) begin if (reset_condition) begin cfg_rst_srl <= 4'b1111; end else if (clk_lock) begin cfg_rst_srl <= {cfg_rst_srl[2:0], 1'b0}; end end assign log_rst = log_rst_srl[3]; always @(posedge log_clk or posedge reset_condition) begin if (reset_condition) begin log_rst_srl <= 4'b1111; end else if (clk_lock) begin log_rst_srl <= {log_rst_srl[2:0], 1'b0}; end end // The Buffer actively manages the reset due to the // nature of the domain crossing being done in the buffer. assign buf_rst = reset_condition; assign phy_rst = phy_rst_srl[3]; always @(posedge phy_clk or posedge reset_condition) begin if (reset_condition) begin phy_rst_srl <= 4'b1111; end else if (clk_lock) begin phy_rst_srl <= {phy_rst_srl[2:0], 1'b0}; end end assign gt_pcs_rst = gt_pcs_rst_srl[3]; always @(posedge gt_pcs_clk or posedge reset_condition) begin if (reset_condition) begin gt_pcs_rst_srl <= 4'b1111; end else if (clk_lock) begin gt_pcs_rst_srl <= {gt_pcs_rst_srl[2:0], 1'b0}; end end // This controller is used to properly send link reset requests that were // made by the user. always@(posedge log_clk) begin reset_state <= reset_next_state; end always @* begin casex (reset_state) IDLE: begin // Current State Outputs sys_rst_int = 1'b0; controlled_force_reinit = 1'b0; // Next State Outputs if (force_reinit) reset_next_state = LINKRESET; else reset_next_state = IDLE; end LINKRESET: begin // Current State Outputs sys_rst_int = 1'b0; controlled_force_reinit = 1'b1; // Next State Outputs if (~port_initialized) reset_next_state = PHY_RESET1; else reset_next_state = LINKRESET; end PHY_RESET1: begin // Current State Outputs sys_rst_int = 1'b1; controlled_force_reinit = 1'b0; // Next State Outputs reset_next_state = PHY_RESET2; end PHY_RESET2: begin // Current State Outputs sys_rst_int = 1'b1; controlled_force_reinit = 1'b0; // Next State Outputs if (force_reinit) reset_next_state = PHY_RESET2; else reset_next_state = IDLE; end default: begin // Current State Outputs sys_rst_int = 1'b0; controlled_force_reinit = 1'b0; // Next State Outputs reset_next_state = IDLE; end endcase end endmodule
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。