赞
踩
未经授权,严禁转载。
本文主要讲解使用Verilog实现CRC串行计算的方法。
CRC在线计算:http://www.ip33.com/crc.html
多项式公式:
G
n
(
x
)
=
g
n
x
n
+
g
n
−
1
x
n
−
1
+
g
n
−
2
x
n
−
2
+
⋯
+
g
2
x
2
+
g
1
x
1
+
1
G_n(x)=g_nx^n+g_{n-1}x^{n-1}+g_{n-2}x^{n-2}+\cdots+g_2x^2+g_1x^1+1
Gn(x)=gnxn+gn−1xn−1+gn−2xn−2+⋯+g2x2+g1x1+1
多项式中 g 0 , g 1 , ⋯ , g n g_0,g_1,\cdots,g_n g0,g1,⋯,gn为0或1,不管多项式是什么样的形式,图1中的 g 0 g_0 g0和 g n g_n gn都为1,其中input_bit为输入的单bit数据(发送数据的某一个bit)。在每个时钟周期下进行一次计算,经过n个时钟周期后得到最终的计算结果。
采用CRC-16/XMODEM计算发送数据的CRC码时,n=16,多项式公式为 G 16 ( x ) = x 16 + x 12 + x 5 + 1 G_{16}(x)=x^{16}+x^{12}+x^{5}+1 G16(x)=x16+x12+x5+1。
CRC算法名称 | 多项式公式 | 宽度 | 多项式 | 初始值 | 结果异或值 | 输入反转 | 输出反转 |
---|---|---|---|---|---|---|---|
CRC-16/XMODEM | x 16 + x 12 + x 5 + 1 x^{16}+x^{12}+x^5+1 x16+x12+x5+1 | 16 | 0x1021 | 0000 | 0000 | false | false |
以计算一个16bit位宽的发送数据的CRC-16/XMODEM码为例,在计算时,首先向串行计算电路中输入发送数据的最高位,再在下一个时钟输入次高位,依次类推,直到发送数据的最低位输入到串行计算电路后,得到最终的CRC码。
(1) 单次计算Verilog代码如下:
模块接口定义:
name | direction | width | description |
---|---|---|---|
data | input | 1 | 串行输入的单bit数据,相当于原理图中的input bit |
crc_pre | input | 16 | 前一个时钟周期运算的crc结果 |
crc | output | 16 | 当前时钟周期下crc运算结果 |
module crc16ccitt_d1( input data, input [15:0] crc_pre, output [15:0] crc ); assign crc[0] = crc_pre[15] ^ data; assign crc[1] = crc_pre[0]; assign crc[2] = crc_pre[1]; assign crc[3] = crc_pre[2]; assign crc[4] = crc_pre[3]; assign crc[5] = crc_pre[4] ^ crc_pre[15] ^ data; assign crc[6] = crc_pre[5]; assign crc[7] = crc_pre[6]; assign crc[8] = crc_pre[7]; assign crc[9] = crc_pre[8]; assign crc[10] = crc_pre[9]; assign crc[11] = crc_pre[10]; assign crc[12] = crc_pre[11] ^ crc_pre[15] ^ data; assign crc[13] = crc_pre[12]; assign crc[14] = crc_pre[13]; assign crc[15] = crc_pre[14]; endmodule
(2) 计算一个16bit数据的CRC码:
模块接口定义:
name | direction | width | description |
---|---|---|---|
clk | input | 1 | 模块时钟信号 |
rst_n | input | 1 | 模块复位信号 |
data_in | input | 16 | 对发送数据data_in计算CRC校验码 |
en | input | 1 | 计算使能信号,单周期高电平有效 |
crc_rst | output | 16 | CRC计算结果 |
crc_rst_vld | output | 1 | CRC计算结果有效标志,单周期高脉冲有效 |
module crc16ccitt_d16( input clk , // 时钟 input rst_n , // 复位 input [15:0] data_in , // 对data_in计算CRC码 input en , // 使能信号 output [15:0] crc_rst , // CRC码 output crc_rst_vld // CRC码有效标志信号 ); reg [15:0] crc_pre ; reg [15:0] data_cal ; reg [ 3:0] cnt ; reg state ; parameter IDLE = 1'b0, SHIFT = 1'b1; always @(posedge clk or negedge rst_n) if (!rst_n) begin state <= IDLE ; data_cal <= 16'd0 ; crc_pre <= 16'd0 ; cnt <= 4'd0 ; end else if (en) begin state <= SHIFT ; data_cal <= data_in ; crc_pre <= 16'd0 ; cnt <= 4'd0 ; end else begin case (state) IDLE : begin state <= IDLE ; data_cal <= 16'd0 ; crc_pre <= 16'd0 ; cnt <= 4'd0 ; end SHIFT : begin data_cal <= data_cal << 1; crc_pre <= crc_rst ; cnt <= cnt + 1'b1; if (cnt == 4'd14) state <= IDLE; else state <= SHIFT; end default: begin data_cal <= 16'd0 ; cnt <= 4'd0 ; end endcase end assign crc_rst_vld = (cnt == 4'd15); crc16ccitt_d1 crc16ccitt_d1( .data (data_cal[15]), .crc_pre (crc_pre ), .crc (crc_rst ) ); endmodule
测试文件:
`timescale 1ns / 1ps module testbench; reg clk ; reg rst_n ; reg [15:0] data_in ; reg en ; wire [15:0] crc_rst ; wire crc_rst_vld ; initial clk = 0; always #10 clk = ~clk; initial begin rst_n = 1'b0; #100; rst_n = 1'b1; end initial begin data_in = 16'd0; en = 1'b0; #200; @(posedge clk) #5; data_in = 16'h5afc; en = 1'b1; @(posedge clk) #5; en = 1'b0; #5000; $stop; end crc16ccitt_d16 dut( .clk (clk ), .rst_n (rst_n ), .data_in (data_in ), .en (en ), .crc_rst (crc_rst ), .crc_rst_vld (crc_rst_vld ) ); endmodule
在端口data_in输入16’h5afc,同时拉高en信号一个时钟周期,使能该模块对输入的数据计算CRC码,经过16个时钟周期后,crc_rst_vld信号变为高电平,标志计算结果crc_rst有效,得到计算结果为16’hcfe7。
使用CRC在线计算工具,计算16’h5afc的CRC-16/XMODEM码,计算结果同样为CFE7。
以上就是本文介绍的内容,本文简要介绍了CRC码的串行计算的原理以及过程,并且给出了Verilog代码和仿真结果。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。