CRC16校验原理与Verilog实现详解_crc16校验码的原理
一、CRC校验基础概念
CRC(Cyclic Redundancy Check,循环冗余校验)是一种常用的数据校验方法,广泛应用于通信协议、存储系统等地方。CRC16特指生成16位校验码的CRC算法。
1.1 CRC核心特点
-
检错能力强:可检测所有单比特和双比特错误
-
计算效率高:适合硬件实现
-
灵活性好:可通过不同多项式适应各种场景
1.2 常见CRC16标准
二、CRC16算法原理
2.1 基本计算过程
-
初始化:寄存器赋初值(通常全0或全1)
-
数据输入:逐位或逐字节处理
-
多项式除法:通过异或运算实现
-
结果输出:最终寄存器值即为CRC
2.2 关键运算图解
数据位:D[7:0]
CRC寄存器:C[15:0]
计算步骤:
1.D与C低8位异或 → T[7:0] = D ^ C[7:0]
2.将T移入CRC寄存器高8位,同时将原高8位移至低8位(等效8次位移)
3.对CRC寄存器进行8次位移和条件异或(完成剩余8次位移)
三、Verilog RTL实现(带详细注释)
3.1 参数化设计核心模块
verilog
/**
* CRC16校验模块(参数化设计)
* @param POLY 生成多项式(默认0x8005)
* @param INIT 初始值(默认0x0000)
* @param REFIN 输入数据是否位反转(默认1)
* @param REFOUT 输出结果是否位反转(默认1)
*/
module crc16 #(
parameter POLY = 16\'h8005,
parameter INIT = 16\'h0000,
parameter REFIN = 1,
parameter REFOUT = 1
)(
input clk, // 系统时钟
input rst_n, // 低有效复位
input [7:0] data_in,// 输入数据(8bit/cycle)
input data_valid, // 数据有效信号
output reg [15:0] crc_out, // CRC16校验结果
output reg crc_ready // 校验完成标志
);
// 当前CRC计算值寄存器
reg [15:0] crc_reg;
// 输入数据位反转处理
wire [7:0] data = REFIN ? {data_in[0], data_in[1], data_in[2], data_in[3],
data_in[4], data_in[5], data_in[6], data_in[7]}
: data_in;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
// 复位初始化
crc_reg <= INIT;
crc_ready <= 1\'b0;
end
else if (data_valid) begin
// 数据有效时进行计算
crc_ready <= 1\'b0;
// 步骤1:输入数据与CRC高字节异或
crc_reg[15:8] <= crc_reg[7:0] ^ data;
crc_reg[7:0] <= crc_reg[15:8];
// 步骤2:8次位移和条件异或
for (int i=0; i<8; i=i+1) begin
if (crc_reg[15]) begin // 最高位为1时执行多项式异或
crc_reg <= {crc_reg[14:0], 1\'b0} ^ POLY;
end else begin // 否则仅位移
crc_reg <= {crc_reg[14:0], 1\'b0};
end
end
end
else begin
// 数据无效时标志计算完成
crc_ready <= 1\'b1;
end
end
// 输出结果位反转处理
assign crc_out = REFOUT ? {crc_reg[0], crc_reg[1], crc_reg[2], crc_reg[3],
crc_reg[4], crc_reg[5], crc_reg[6], crc_reg[7],
crc_reg[8], crc_reg[9], crc_reg[10], crc_reg[11],
crc_reg[12], crc_reg[13], crc_reg[14], crc_reg[15]}
: crc_reg;
endmodule
3.2 单周期并行计算优化
verilog
/**
* 单周期CRC16并行计算模块
* 适用于高速数据处理场景
*/
module crc16_parallel #(
parameter POLY = 16\'h8005
)(
input [15:0] crc_in, // 当前CRC值
input [7:0] data, // 输入数据
output [15:0] crc_out // 新CRC值
);
// 中间计算结果
wire [15:0] d = {8\'h00, data} ^ crc_in;
// 并行计算逻辑展开
assign crc_out = {
d[14:8], // bit[15:9]
d[7]^d[15], // bit8
d[6], // bit7
d[5], // bit6
d[4], // bit5
d[3], // bit4
d[2], // bit3
d[1], // bit2
d[0]^d[15], // bit1
d[15]^d[14], // bit0
d[15]^d[13], // bit15
d[15]^d[12], // bit14
d[15]^d[11], // bit13
d[15]^d[10], // bit12
d[15]^d[9], // bit11
d[15]^d[8] // bit10
};
endmodule
四、应用场景与实例
4.1 工业通信协议(Modbus RTU)
verilog
// Modbus RTU CRC校验实例
crc16 #(
.POLY(16\'h8005),
.INIT(16\'hFFFF),
.REFIN(1),
.REFOUT(1)
) modbus_crc (
.clk(uart_clk),
.rst_n(sys_rst_n),
.data_in(rx_data),
.data_valid(rx_valid),
.crc_out(modbus_crc_result)
);
// 帧校验逻辑
always @(posedge clk) begin
if (frame_end) begin
if (modbus_crc_result == 16\'h0000)
crc_ok <= 1\'b1;
else
crc_error <= 1\'b1;
end
end
4.2 存储系统数据校验
verilog
// NAND Flash数据校验
crc16 #(
.POLY(16\'h1021),
.INIT(16\'hFFFF),
.REFIN(0),
.REFOUT(0)
) flash_crc (
.clk(nand_clk),
.rst_n(!nand_reset),
.data_in(flash_data),
.data_valid(data_rdy),
.crc_out(flash_crc_result)
);
// 写入时生成CRC
always @(posedge nand_clk) begin
if (write_en) begin
flash_data_out <= {user_data, flash_crc_result};
end
end