CRC设计
一、以CRC-16-USB x16+x15+x2+1的多项式为例
CRC设计需要考虑CRC初始值,输入值反转,输出值反转,结果异或值这些条件;
(1)初始值为移位寄存器的初始值;
(2)输入值反转指的是以字节为单位进行反序,例如16‘hff_f0反序后为16’hff_0f;
(3)输出反序为按照bit进行反序;
(4)结果异或值是对结果异或处理,它在crc执行步骤中为输出反序之前;
CRC电路算法实际是基于线性反馈移位寄存器;
二、下面给出设计代码
1、支持特性
(1)采用CRC的串行方式计算,17个时钟周期输出结果(性能有待提升);
(2)非流水线形,只能处理单次CRC计算,未处理完发送下一笔数据上一笔会丢失;
(3)初始值,结果异或值,输入逆序,输出逆序寄存器可配置;
2、RTL代码
//CRC-16-USB x16+x15+x2+1
//serial CRC
module CRC_16_USB #(
parameter DATA_SIZE = 16,
parameter CRC_SIZE= 16
)
(
input clk,
input rst_n,
input [DATA_SIZE-1:0] data_in,
input vlid_i,
output reg [CRC_SIZE-1:0] crc_out,
output reg vlid_o
);
//reg [CRC_SIZE-1:0] crc_poly = 16'h8005;
localparam init_value_reg = 16'hffff;
reg [CRC_SIZE-1:0] init_value;
reg [CRC_SIZE-1:0] xor_value = 16'hffff;
reg refin = 1'b1;
reg refout = 1'b1;
reg [DATA_SIZE-1:0] refin_data;
reg [DATA_SIZE-1:0] refout_data;
reg [4:0] cnt;
reg [DATA_SIZE-1:0] vlid_data;
//reg finish_flag;
reg start;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
vlid_data <= 16'h0;
end
else if(vlid_i == 1'b1);
vlid_data <= data_in;
end
always@(*)begin
for(integer i=0; i<8; i++)begin
if(refin == 1'b1)begin
refin_data[15-i] = vlid_data[8+i]; //reverse by byte
refin_data[7-i] = vlid_data[i];
end
else
refin_data[i] = data_in[i];
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= 5'b0;
end
else if(vlid_i == 1'b1)
cnt <= 5'b0_1111;
else if(cnt > 5'b0)
cnt <= cnt - 5'b1;
else
cnt <= cnt;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
start <= 1'b0;
end
else if(vlid_i == 1'b1)
start <= 1'b1;
else if(start == 1'b1 && cnt == 5'b0)
start <= 1'b0;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
vlid_o <= 1'b0;
end
else if(start == 1'b0)
vlid_o <= 1'b0;
else if(cnt == 5'b0 && start == 1'b1)
vlid_o <= 1'b1;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
init_value <= init_value_reg;
end
else if(vlid_i == 1'b1)
init_value <= init_value_reg;
else if(start == 1'b0)
init_value <= init_value;
else
init_value = {init_value[14]^init_value[15]^refin_data[cnt], init_value[13], init_value[12], init_value[11], init_value[10], init_value[9], init_value[8], init_value[7], init_value[6], init_value[5], init_value[4], init_value[3], init_value[2], init_value[1]^init_value[15]^refin_data[cnt], init_value[0], init_value[15]^refin_data[cnt]};
end
always@(*)begin
refout_data = init_value[15:0]^xor_value[15:0];
end
always@(*)begin
for(integer k=0;k<16; k++)begin
if(refout == 1'b1)
crc_out[k] = refout_data[15-k];
else
crc_out[k] = refout_data[k];
end
end
endmodule
3、简单的TestBench示例
`timescale 1ns/10ps
module top_tb();
logic clk;
logic rst_n;
logic vlid_i;
logic [15:0] data_in;
logic [15:0] data_out;
CRC_16_USB #(
.DATA_SIZE(16),
.CRC_SZIE(16)
) u_crc_16_usb (
.data_in(data_in),
.clk(clk),
.vlid_i(vlid_i),
.vlid_o(vlid_o),
.rst_n(rst_n),
.crc_out(data_out)
);
initial begin
clk = 0;
forever begin
#10 clk = ~clk;
end
end
initial begin
rst_n = 0;
vlid_i = 0;
data_in = 0;
#100ns;
rst_n = 0;
#10ns;
rst_n = 1;
vlid_i = 1;
data_in = $urandom()%65536;
#20ns;
vlid_i = 0;
#60ns;
vlid_i = 1;
data_in = $urandom()%65536;
#20ns;
vlid_i = 0;
#10ns;
wait(vlid_o == 1);
#100ns;
vlid_i = 1;
data_in = $urandom()%65536;
#50ns;
vlid_i = 0;
#500ns;
$finish();
end
initial begin
$fsdbDumpfile("tb.fsdb");
$fsdbDumpvars;
end
endmodule
4、Makefile脚本
all: clean elab sim verdi
elab:
vcs -sverilog -full64 -debug_all +fsdb+region -timescale=1ns/1ps \
-f filelist.f \
-top top_tb \
-P ${VERDI_HOME}/share/PLI/VCS/LINUX64/novas.tab ${VERDI_HOME}/share/PLI/VCS/LINUX64/pli.a \
-l com.log \
-cm cond+line+tgl+branch+fsm+assert
sim:
./simv +fsdb+delta -cm cond+line+tgl+branch+fsm+assert -l sim.log
verdi:
verdi -sv -f filelist.f -ssf ./tb.fsdb &
clean:
rm -rf AN.DB csrc
rm -rf *simv*
rm -rf DVEfiles
rm -rf ucli.key
rm -rf *.fsdb *.log *.conf
三、运行结果
1、fsdb波形
2、覆盖率收集
verdi的cov未破解的解决方案如下
killall lmgrd,杀死所有的lmgrd进程;
在已有的破解工具的src文件加入VerdiCoverage关键词