文章目录
前言
通过对时钟和复位的理解可以更好的了解IP核的工作过程,不过不理解也不影响使用,example design帮我们都做好了。
一、时钟
可以直接看总结
1.1、整体说明
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。
1.2、典型时钟速率
下表是xilinx给出的典型时钟速率,我们以4x为例进行分析:
- 首先是gt_clk 和gt_pcs_clk,这个是根据线速率决定的,从下面的图3-14也可以看出,所谓的gt_clk就是我们之前熟悉的TXUSERCLK/RXUSERCLK,gt_pcs_clk就是我们之前熟悉的TXUSERCLK2/RXUSERCLK2,这也就可以很好的理解为什么他俩之间是二倍的关系了。
- 对于phy_clk,根据计算公式phy_clk= (gt_clk * 链路Line宽度)/4 ,所以phy_clk= gt_clk
- log_clk则是不能小于phy_clk,所以大于等于最大phy_clk。
下图当中的示例设计采用单个差分输入时钟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绑定。
1.3、时钟总结
IP核当中有6个时钟输入,简单总结如下:
- gt_clk:由链路速率决定
- gt_pcs_clk: gt_pcs_clk的频率是gt_clk的一半。
- phy_clk:phy_clk= (gt_clk * 链路Line宽度)/4
- log_clk :LOG(逻辑层)在log_clk域上运行。为了达到最佳吞吐量,log_clk应至少与phy_clk一样快。这是为了PHY层接收到的数据不会在BUF里一直停留。cfg_clk必须等同于log_clk
- drpclk :动态配置时钟,随意
- refclk :GT外部参考时钟
1.4、示例工程
这是示例工程当中的时钟模块,它将我们需要的时钟全部都已经产生好了,其中输入时钟信号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
标签:reset,gt,clk,IP,unused,phy,SRIO,rst,时钟
From: https://blog.csdn.net/m0_56222647/article/details/137476370