图1:debug设计添加位置
图2:ltssm状态切换图
LTSSM state: LTSSM state encoding: • 00h: detect.quiet • 01h: detect.active • 02h: polling.active • 03h: polling.compliance • 04h: polling.configuration • 05h: config.linkwidthstart • 06h: config.linkwidthaccept • 07h: config.lanenumwait • 08h: config.lanenumaccept • 09h: config.complete • 0Ah: config.idle • 0Bh: recovery.receiverlock • 0Ch: recovery.equalization | • 0Dh: recovery.speed • 0Eh: recovery.receiverconfig • 0Fh: recovery.idle • 10h: L0 • 11h: L0s • 12h: L1.entry • 13h: L1.idle • 14h: L2.idle/L2.transmitwake • 15h: reserved • 16h: disable • 17h: loopback.entry • 18h: loopback.active • 19h: loopback.exit • 1Ah: hotreset |
i_pcie_ltssm作为PCIe链路训练状态机的实时状态,能够有效显示当前链路的链路状态。
一旦PCIe出现问题,i_pcie_ltssm最近的数值跳变情况是进行分析的重要依据。本节采用移位寄存器实现了一种简单的锁存机制,能够锁存最近若干个(锁存个数已参数化)的数值。
图3 pcie_ltssm_debug波形图
如图所示,i_pcie_ltssm作为输入信号,每隔一段时间会发生变化,o_latch_ltssm作为状态锁存信号会送到cfg_csr模块。在如下代码波形中,o_latch_ltssm锁存了i_pcie_ltssm最近的10次数值,pcie_ltssm数值发生变化,则锁存一次。
o_latch_ltssm[#n][5] 为1(#n表示1~9)表示o_latch_ltssm[#n][4:0] 为有效锁存数据。
o_latch_ltssm[0][5:0] 表示最新的锁存结果
o_latch_ltssm[9][5:0] 表示最早的锁存结果
案例中代码采用移位的方式实现了i_pcie_ltssm数值的锁存,当i_pcie_ltssm数值发生变化,则由o_latch_ltssm[0][4:0]锁存最新的pcie_ltssm,o_latch_ltssm[0][5]置1表示当前锁存数值有效,而o_latch_ltssm[0][5:0] 锁存的数据则赋值给o_latch_ltssm[1][5:0] ,o_latch_ltssm[1][5:0] 锁存的数据则赋值给o_latch_ltssm[2][5:0] ,以此类推,o_latch_ltssm[8][5:0] 锁存的数据则赋值给o_latch_ltssm[9][5:0] ,而o_latch_ltssm[9][5:0]的锁存数据因为无处可存了,因此直接丢弃了。
module pcie_ltssm_debug
#( parameter LTSSM_LATCH_NUM=10)
(
input clk , //
input rst_n , //
input [5-1:0] i_pcie_ltssm , //
output reg [LTSSM_LATCH_NUM-1:0] [6-1:0] o_latch_ltssm //
);
reg [5-1:0] i_pcie_ltssm_d1 ; //
reg [LTSSM_LATCH_NUM-1:0] latch_ltssm_vld ; //
always@(posedge clk)
if(!rst_n) begin
i_pcie_ltssm_d1 <= 'b0 ;
end
else begin
i_pcie_ltssm_d1 <= i_pcie_ltssm ;
end
assign latch_ltssm_vld = (i_pcie_ltssm_d1!=i_pcie_ltssm) ; //
for (genvar i=0;i<LTSSM_LATCH_NUM;i=i+1) begin: latch_shift
if(i==0) begin
always@(posedge clk)
if(!rst_n) begin
o_latch_ltssm[i][5-1:0] <= 'b0 ;
o_latch_ltssm[i][5] <= 'b0 ;
end
else if(latch_ltssm_vld) begin
o_latch_ltssm[i][5-1:0] <= i_pcie_ltssm ;
o_latch_ltssm[i][5] <= 'b1 ;
end
end
else //i>0
begin
always@(posedge clk)
if(!rst_n) begin
o_latch_ltssm[i][5-1:0] <= 'b0 ;
o_latch_ltssm[i][5] <= 'b0 ;
end
else if((latch_ltssm_vld&&o_latch_ltssm[i-1][5]) ) begin
o_latch_ltssm[i][5-1:0] <= o_latch_ltssm[i-1][5-1:0] ;
o_latch_ltssm[i][5] <= o_latch_ltssm[i-1][5] ;
end
end
end
endmodule