累加和校验原理与FPGA实现
累加和校验原理与FPGA实现
- 写在前面
- 一、基础原理
- 二、举个例子
- 2.1 进位累加
- 2.2 回卷累加
- 三、FPGA实现
- 3.1 发送端(产生校验和)
- 3.2 接收端(累加和校验)
- 3.3 仿真结果
- 写在后面
写在前面
在上文《奇偶校验原理与FPGA实现》中,讲解了奇偶校验的基础原理,奇偶校验仅增加1比特的信息冗余,所增加额外开销小,但不可避免存在检错能力有限的问题。本文将讲解另外一种校验码型——累加和校验。累加和校验的使用场景较为广泛,在网络通信协议(IP/TCP/UDP协议)、高速接口(AXI)、存储器数据保护等很多场景均有使用。
一、基础原理
累加和校验原理是将要发送或存储的数据分割成固定长度的多个数据段(通常为字节或字),然后将这些数据段累加起来(通常采用二进制加法,忽略进位),得到一个累加和。最后,将累加和取反(或取补码)作为校验值附加到原始数据后面。
在发送端,累加和的计算可以分为以下几个步骤:
- 数据分割:将数据按固定长度(如8位、16位)分割成多个数据块;
- 累加求和:将所有数据块进行二进制加法累加。在累加过程中,如果有进位,则回卷(即进位加到最低位上)。但实际实现中,通常采用足够宽的寄存器(如16位累加和用32位寄存器)来避免溢出,最后取低16位;
- 取反:将累加和按位取反(即1的补码),得到校验和(Checksum)。取反的目的是为了在接收端验证时,包括校验和在内的所有数据累加的结果应该为全1(即0xFFFF,对于16位校验和),再取反则为0。这样接收端可以通过判断累加结果是否为0来检查数据正确性;
- 附加校验和:将计算得到的校验和附加在原始数据的末尾;
而在接收端,将接收到的所有数据(包括原始数据和附加的校验和)进行同样的累加操作(同样忽略进位或使用足够宽的寄存器),如果传输没有错误,则累加的结果应该为0xFFFF。
以上描述的校验和传输方式为反码传输,实际上常用的校验和传输方式有原码、反码、补码三种。
- 方式1:发送方计算数据的累加和,然后将其作为校验和直接发送。接收方将接收到的所有数据(不包括校验和)进行累加,如果没有错误,则累加结果应该与校验和一致。
- 方式1:发送方计算数据的累加和,然后取反码作为校验和进行发送。接收方将接收到的所有数据(包括校验和)进行累加,如果没有错误,则结果应为全1(即0xFFFF,对于16位校验和)。因为:原码+反码=全1。
- 方式2:发送方计算数据的累加和,然后取补码作为校验和进行发送。接收方将接收到的所有数据(包括校验和)进行累加,如果没有错误,则结果应为全0。因为:原码+补码=全0
二、举个例子
以反码形式传输校验和为例,假如传输的4个16比特数据分别为0x1234、0x5678、0x9ABC、0xDEF0。
2.1 进位累加
若是使用进位累加的方式,采用32位累加器(保证累加和不溢出),则在发送端:
取累加和的低16比特0xE258,取反得到校验和0x1DA7进行发送。在接收端:
累加结果的低16比特为全1,累加和校验通过。
2.2 回卷累加
若是使用进位累加的方式,采用17位累加器,则在发送端:
取累加和的低16比特0xE258,取反得到校验和0x1DA6进行发送。在接收端:
累加结果的低16比特为全1,累加和校验通过。
三、FPGA实现
3.1 发送端(产生校验和)
module tx_checksum
(input clk ,input rst_n ,input [15 :0] data_in , // 输入数据input data_valid , // 数据有效信号input start , // 数据起始标志input finish , // 数据结束标志output [15 :0] checksum , // 生成的校验和output checksum_valid // 校验和有效信号
);//----------------------------------------------------------------// REG//----------------------------------------------------------------reg [31 :0] accumulator ; // 32位累加器(防溢出)reg finish_d ;//----------------------------------------------------------------// LOGIC//----------------------------------------------------------------always @(posedge clk or negedge rst_n) beginif(!rst_n)accumulator <= 32'd0;else if(start && data_valid)accumulator <= {16'd0,data_in};else if(data_valid)accumulator <= accumulator[31:16] + accumulator[15:0] + data_in; // 回卷+累加elseaccumulator <= accumulator;endalways @(posedge clk or negedge rst_n) beginif(!rst_n)finish_d <= 1'b0;elsefinish_d <= finish;endassign checksum = ~accumulator[15:0];assign checksum_valid = finish_d ;endmodule
3.2 接收端(累加和校验)
module rx_checksum
(input clk ,input rst_n ,input [15 :0] data_in , // 输入数据input data_valid , // 数据有效信号input start , // 数据起始标志input finish , // 数据结束标志output check_pass // 数据校验通过
);//----------------------------------------------------------------// REG//----------------------------------------------------------------reg [31 :0] accumulator ; // 32位累加器(防溢出)reg finish_d ;//----------------------------------------------------------------// LOGIC//----------------------------------------------------------------always @(posedge clk or negedge rst_n) beginif(!rst_n)accumulator <= 32'd0;else if(start && data_valid)accumulator <= {16'd0,data_in};else if(data_valid)accumulator <= accumulator[31:16] + accumulator[15:0] + data_in; // 回卷+累加elseaccumulator <= accumulator;endalways @(posedge clk or negedge rst_n) beginif(!rst_n)finish_d <= 1'b0;elsefinish_d <= finish;endassign check_pass = (finish_d && (accumulator == 32'h0000FFFF)) ? 1'b1 : 1'b0;endmodule
3.3 仿真结果
在发送端,依次发送0x1234、0x5678、0x9ABC、0xDEF0,得到的校验和为0x1DA6,与前面所举例子理论值一致。
在发送端,对序列0x1234、0x5678、0x9ABC、0xDEF0、0x1DA6进行累加,得到的累加和为0xFFFF,校验通过。
写在后面
在本文中,讲解了累加和校验的基本原理,包括:
- 累加和的三种传输方式以及在接收端相应的校验方法(原码、反码、补码)
- 累加的两种方式(进位累加、回卷累加)
同时,举例计算进位累加与回卷累加的累加过程与校验过程,并给出了回卷累加的发送端、接收端代码与仿真结果。
🧐:以上为个人学习笔记,如有疑问,欢迎评论区交流探讨 !!!
