http://bbs.ednchina.com/BLOG_ARTICLE_3018596.HTM
在高速设计中,为了测试高速串行通道传输的误码率,通常通过发送PRBS码来进行测试
原理:用生产函数产生一段随机码流,然后按周期循环。
PRBS码的周期长度与其阶数有关,常用的阶数有7,9,11,15,20,23,31.
对于N阶PRBS码,每个周期的序列长度为2^N-1.
在每个周期内,0和1时随机分布的,并且0和1的个数相等。
连续个1的最大数目为n,连续个0的最大数目为n-1(反转后就是n-1个连续1和n个连续0)。
在对高速信号链路进行误码测试时,基本上都是利用PRBS码流来模拟真实的线网码流环境,因为在线网中,所有的数据都是随机出现的,没有任何规律可言,而PRBS码流在一定程度上具有这种“随机数据”特性,二进制0和1随机出现,其频谱特征与白噪声非常接近。PRBS码流的阶数越高,其包含的码流就越丰富,就越接近真实的线网环境,测试的结果就越准确。
一个PRBS序列可以串/并转换成多路(2、4、8、16.路),每路输出的速率降低,但仍然保持原序列的所有特诊,反之,同一时钟源低速多路(2、4、8、16..路)同一个n数的PRBS可以经并/串转换成高速率的n阶PRBS。
下面采用verilog来设计PRBS模块,可以通过外部参数配置PRBS7, PRBS9, PRBS15, PRBS23, PRBS31,
`timescale 1ns / 1ps
module prbs_gen
#(
parameter PRBS_WIDTH = 32,
parameter PRBS_PATTERN = "prbs7" //prbs7,prbs9.prbs15,prbs23,prbs31
)
(
input sys_clk, //系统时钟
input reset_n, //系统复位
input prbs_en, //enable_prbs
input inser_err,
output [PRBS_WIDTH-1:0] prbs_data //prbs_out
);
reg [PRBS_WIDTH-1:0] prbs_reg;
reg [PRBS_WIDTH-1:0] tx_data;
wire feed_data;
wire [PRBS_WIDTH-1:0] prbs_d;
integer m;
//本原多项式
//prbs7 = 1+x^6+x^7
//prbs9 = 1+x^5+x^9
//prbs15 = 1+x^14+x^15
//prbs23 = 1+x^18+x^23
//prbs31 = 1+x^28+x^31
localparam PRI_MAX_WIDTH = 40;
wire [PRI_MAX_WIDTH-1:0] prbs_pri_val;
reg prbs_en_d0,prbs_en_d1;
assign prbs_pri_val = (PRBS_PATTERN == "prbs7")? 40'b0011000001:
(PRBS_PATTERN == "prbs9")? 40'b1000100001:
(PRBS_PATTERN == "prbs15")? 40'b0000110000__0000000001:
(PRBS_PATTERN == "prbs23")? 40'b0000001000_0100000000_1000100001:
(PRBS_PATTERN == "prbs31")? 40'b0000000010_0100000000_0000000000_0000000001:0011000001;
localparam reset_seed = 40'haa_aaaa_aaaa;
always @(posedge sys_clk or negedge reset_n) begin
if(~reset_n) begin
prbs_en_d0 <= #1 'b0;
prbs_en_d1 <= #1 'b0;
end
else begin
prbs_en_d0 <= #1 prbs_en;
prbs_en_d1 <= #1 prbs_en_d0;
end
end
always @(posedge sys_clk or negedge reset_n) begin
if(reset_n == 1'b0) begin
prbs_reg <= prbs_pri_val[(PRBS_WIDTH-1):0];
//prbs_reg <= prbs_pri_val[7:0];
end
else if(prbs_en_d1) begin
for(m =1; m< PRBS_WIDTH; m = m+1)
prbs_reg[PRBS_WIDTH-m-1] <= prbs_reg[PRBS_WIDTH-m];
prbs_reg[PRBS_WIDTH-1] <= feed_data;
end
else
prbs_reg[PRBS_WIDTH-1:0] <= prbs_reg[PRBS_WIDTH-1:0];
end
assign prbs_d = prbs_reg & prbs_pri_val[(PRBS_WIDTH-1):0];
assign feed_data = ^prbs_d;
reg inser_err_d0;
reg inser_err_d1;
reg detect_insererr;
always @(posedge sys_clk or negedge reset_n) begin
if(reset_n == 1'b0) begin
tx_data <= reset_seed[PRBS_WIDTH-1:0];
inser_err_d0 <= 1'b0;
inser_err_d1 <= 1'b0;
detect_insererr <= 1'b0;
end
else begin
inser_err_d0 <= inser_err;
inser_err_d1 <= inser_err_d0;
if(inser_err_d0 == 1'b1 && inser_err_d1 == 1'b0)
detect_insererr <= 1'b1;
else
detect_insererr <= 1'b0;
if(detect_insererr == 1'b1)
tx_data <= {~prbs_reg[PRBS_WIDTH-1],prbs_reg[PRBS_WIDTH-2:0]};
else
tx_data <= prbs_reg[PRBS_WIDTH-1:0];
end
end
assign prbs_data = tx_data;
endmodule