一、前言
上一篇讲述了SRIO协议的基本概念,传输的HELLO帧格式、事务类型等,本篇说一下SRIO IP核的时钟关系。
基本的IP设置可以参考此篇文章:【高速接口-RapidIO】Xilinx SRIO IP 核详解-CSDN博客
二、时钟关系
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)。当生成核心时,参考时钟频率被选择(可用选项取决于体系结构和线路速率。
时钟 | 频率关系 | |
phy_clk | phy_clk = (gt_clk * link width)/4 | 主要的核时钟 |
gt_pcs_clk | gt_pcs_clk = 1/2 * gt_clk | 主要终于Serial Transceiver interface |
refclk | 见下表 | 用于Serial Transceiver interface |
log_clk | log_clk >=phy_clk | |
cfg_clk | cfg_clk = log_clk | 配置寄存器接口时钟 |
不同lane下的时钟关系:
对于7系列FPGAs,使用MMCM从串行收发器(GT)参考时钟生成时钟。时钟方案的方框图如下:
在SRIO的例子工程中,时钟主要有共享逻辑中的时钟模块提供,在这个模块中通过MMCM得到满足上述时钟关系的各时钟域时钟。
srio_gen2_0_srio_clk
srio_clk_inst (
.sys_clkp (sys_clkp ),// input to the clock module
.sys_clkn (sys_clkn ),// input to the clock module
.sys_rst (sys_rst ),// input to the clock module
.mode_1x (mode_1x ),// input to the clock module
.log_clk (log_clk_out ),// output from clock module
.phy_clk (phy_clk_out ),// output from clock module
.gt_clk (gt_clk_out ),// output from clock module
.gt_pcs_clk (gt_pcs_clk_out ),// output from clock module
.refclk (refclk_out ),// output from clock module
.drpclk (drpclk_out), // output from clock module
.clk_lock (clk_lock_out_int) // output from clock module
);
二、复位逻辑
SRIO每个时钟域都有一个指定的复位,复位应该声明各自时钟域的至少四个时钟周期,并同步取消复位。
在例子工程的复位模块中,会有一个异步的复位输入,在这个模块中,会将这个复位同步到各个时钟域,并且需要把复位的脉冲扩展到最小的复位时钟周期请求。
当重置SRIO端点设备时必须要将链路两端的设备一起复位,去保证AckID的对齐,从而减少数据包和控制字符的丢失。实现这一过程的方式是对核的复位进行握手。从接收端接收到的复位信号会通过phy_rcvd_link_reset给到用户设计。在接收到链路重置时应该置位sys_rst信号,还可以向用户应用程序响应phy_rcvd_link_reset的断言。
向对端发送重置请求,请求置位phy_rcvd_link-reset信号,直到端口初始化输出变低。
在例子工程中,srio_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