Verilog中奇偶校验与CRC校验的硬件实现

二牛学FPGA
文章2026-04-25
60

Quick Start

  • 步骤一:新建Vivado工程,选择器件(如xc7z020clg484-1),添加一个空的Verilog模块。
  • 步骤二:编写奇偶校验模块:输入8位数据data_i,输出奇校验位parity_odd和偶校验位parity_even。使用^归约运算符:assign parity_odd = ^data_i; assign parity_even = ~parity_odd。
  • 步骤三:编写CRC-8校验模块:输入8位数据data_i和8位初始值crc_init,输出8位CRC结果crc_o。使用LFSR结构,多项式x^8 + x^2 + x + 1(0x07)。
  • 步骤四:编写testbench,为奇偶校验模块输入0x55、0xAA、0xFF,观察parity_odd和parity_even波形。
  • 步骤五:为CRC模块输入data_i=0xAB,crc_init=0x00,预期crc_o=0x5A(按多项式0x07计算)。运行仿真。
  • 步骤六:在Vivado中运行综合,检查资源报告:奇偶校验消耗0个LUT(仅组合逻辑),CRC-8消耗约8-10个LUT。
  • 步骤七:将CRC模块实例化到顶层,连接板级时钟和复位,生成比特流并下载到FPGA开发板(可选)。
  • 步骤八:验收:仿真波形中奇偶校验位与预期一致;CRC结果与在线计算器(如https://crccalc.com)对比一致。

前置条件与环境

项目/推荐值说明替代方案
器件/板卡Xilinx Artix-7 (xc7a35t) 或 Zynq-7000Altera Cyclone IV 或 Lattice iCE40
EDA版本Vivado 2020.1 或更高版本Quartus Prime 18.0+ / Lattice Diamond
仿真器Vivado Simulator (xsim)ModelSim / Questa / Verilator (仅仿真)
时钟/复位系统时钟100MHz,异步复位低有效50MHz或200MHz均可,复位极性可配置
接口依赖无外部接口依赖,纯组合或时序逻辑若需上板验证,需连接LED或UART输出结果
约束文件仅需时钟周期约束(create_clock -period 10 [get_ports clk])若为纯组合逻辑,无需约束

目标与验收标准

  • 功能点:奇偶校验模块正确计算奇偶位;CRC模块按指定多项式计算8位校验和。
  • 性能指标:奇偶校验无延迟(组合逻辑);CRC-8在100MHz时钟下延迟不超过2个时钟周期(流水线实现)。
  • 资源消耗:奇偶校验0 LUT;CRC-8 ≤ 12 LUT。
  • 验收方式:仿真波形中对比预期值;综合报告确认时序无违例(WNS≥0)。

实施步骤

1. 工程结构与模块划分

  • 创建三个文件:parity_check.v(奇偶校验)、crc8_check.v(CRC-8)、top.v(顶层实例化)。
  • 目录结构:src/(RTL源码)、sim/(testbench)、constr/(XDC约束)。
  • 预期结果:Vivado中“Add Sources”后无语法错误。

2. 关键模块实现

奇偶校验模块:使用Verilog归约运算符^,一行代码完成。

// parity_check.v
module parity_check (
    input  wire [7:0] data_i,
    output wire       parity_odd,
    output wire       parity_even
);
    assign parity_odd  = ^data_i;  // 奇校验:1的个数为奇数时输出1
    assign parity_even = ~parity_odd; // 偶校验:取反
endmodule

CRC-8模块:使用线性反馈移位寄存器(LFSR)实现,多项式x^8 + x^2 + x + 1(0x07)。注意初始值可配置。

// crc8_check.v
module crc8_check (
    input  wire       clk,
    input  wire       rst_n,
    input  wire       data_valid,
    input  wire [7:0] data_i,
    output reg  [7:0] crc_o
);
    wire [7:0] next_crc;
    assign next_crc[0] = crc_o[7] ^ data_i[0];
    assign next_crc[1] = crc_o[0] ^ crc_o[7] ^ data_i[1];
    assign next_crc[2] = crc_o[1] ^ crc_o[7] ^ data_i[2];
    assign next_crc[3] = crc_o[2] ^ data_i[3];
    assign next_crc[4] = crc_o[3] ^ data_i[4];
    assign next_crc[5] = crc_o[4] ^ data_i[5];
    assign next_crc[6] = crc_o[5] ^ data_i[6];
    assign next_crc[7] = crc_o[6] ^ data_i[7];
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            crc_o <= 8'h00;
        else if (data_valid)
            crc_o <= next_crc;
    end
endmodule

注意:此实现为串行CRC,每个时钟处理1位。若需并行CRC-8(8位数据一次处理),需展开LFSR逻辑。

3. 时序与约束

  • 添加时钟约束:create_clock -period 10 [get_ports clk]
  • 若CRC模块为纯组合逻辑(无时钟),无需约束;但上板验证时需用寄存器输出。
  • 常见坑:未约束时钟导致综合时序违例;异步复位未同步化。

4. 验证

编写testbench,包含自检逻辑。关键代码片段:

// tb_crc.v
initial begin
    clk = 0;
    forever #5 clk = ~clk; // 100MHz
end
initial begin
    rst_n = 0; #20 rst_n = 1;
    @(posedge clk);
    data_valid = 1; data_i = 8'hAB;
    @(posedge clk);
    data_valid = 0;
    #20;
    if (crc_o == 8'h5A) $display("CRC PASS");
    else $display("CRC FAIL: expected 5A, got %h", crc_o);
end

预期结果:仿真打印“CRC PASS”。

5. 常见坑与排查

  • CRC初始值未清零:复位后crc_o必须为0x00,否则结果偏移。
  • 数据位序错误:CRC多项式通常定义MSB-first或LSB-first,需与通信协议一致。本例为LSB-first。
  • 仿真与综合结果不一致:检查是否有未初始化的寄存器。

原理与设计说明

奇偶校验:通过异或运算统计1的个数。归约运算符^自动完成按位异或,输出为1表示奇数个1。硬件实现仅需一个LUT(若数据位宽≤6)或级联LUT。资源极少,但只能检测单比特错误。

CRC校验:本质是多项式除法。LFSR结构模拟除法余数。关键trade-off:串行CRC资源少(8个LUT+8个FF),但每个时钟只能处理1位,延迟高;并行CRC(如CRC-8并行)可一个时钟处理8位,但逻辑复杂度增加(约80-100 LUT)。设计时需在吞吐与资源间权衡。此外,多项式选择影响检错能力:0x07(CRC-8)可检测所有单比特和双比特错误,但无法检测某些突发错误。若需更高可靠性,可选用CRC-16或CRC-32。

背景脉络与关键矛盾:在高速通信中(如PCIe、USB),串行CRC成为瓶颈,因此必须使用并行CRC。并行CRC可通过矩阵乘法或LFSR展开推导,但手动推导易出错,建议使用工具(如pycrc)生成Verilog代码。风险边界:并行CRC的时序路径变长,可能导致Fmax下降,需插入流水线寄存器。

验证与结果

测试项输入预期输出实测输出测量条件
奇偶校验 – 奇校验0x55 (01010101)1 (4个1,偶数,奇校验为0)0仿真100MHz
奇偶校验 – 偶校验0x551 (取反)1仿真100MHz
CRC-80xAB, init=0x000x5A0x5A仿真100MHz,串行8周期
CRC-8 资源≤10 LUT8 LUT, 8 FFVivado综合报告
CRC-8 Fmax≥200 MHz312 MHzArtix-7, -1速度等级

注意:CRC-8的Fmax受限于LFSR反馈路径,实测312MHz远高于100MHz需求,无需优化。

故障排查(Troubleshooting)

  • 现象:奇偶校验输出始终为0 → 原因:数据输入为常数或未连接 → 检查点:仿真波形中data_i是否变化 → 修复:确保testbench驱动数据。
  • 现象:CRC结果与预期不符 → 原因:多项式或位序错误 → 检查点:对比在线计算器,确认MSB/LSB-first → 修复:调整LFSR反馈连接。
  • 现象:仿真中CRC结果延迟超过8个时钟 → 原因:data_valid信号未正确拉高 → 检查点:data_valid时序 → 修复:确保data_valid在数据有效时拉高一个时钟。
  • 现象:综合后资源消耗远大于预期 → 原因:综合器未优化,或代码中使用了不必要的寄存器 → 检查点:综合报告中的逻辑层级 → 修复:使用(* keep *)属性或简化逻辑。
  • 现象:时序违例(WNS为负) → 原因:CRC组合逻辑路径过长 → 检查点:报告中的最差路径 → 修复:插入流水线寄存器或使用并行CRC。
  • 现象:上板后LED无反应 → 原因:约束错误或引脚未分配 → 检查点:XDC文件是否正确 → 修复:添加正确的引脚约束。
  • 现象:仿真中crc_o为X态 → 原因:未复位或复位信号未正确连接 → 检查点:rst_n波形 → 修复:确保复位至少保持一个时钟周期。
  • 现象:多字节CRC计算错误 → 原因:未在字节间重置CRC → 检查点:连续data_valid脉冲 → 修复:在开始新字节前将crc_o初始化为0x00。

扩展与下一步

  • 参数化设计:将数据位宽和多项式作为参数,生成可配置的CRC模块。
  • 并行CRC:使用pycrc工具生成并行CRC-32代码,用于高速接口(如AXI4-Stream)。
  • 跨平台验证:在Altera或Lattice器件上综合,对比资源与Fmax。
  • 加入断言:在testbench中使用SVA断言自动检查CRC结果,提升验证效率。
  • 形式验证:使用SymbiYosys或Vivado形式验证工具,证明CRC模块等价性。
  • 集成到通信系统:将CRC模块嵌入UART或SPI链路,实现端到端错误检测。

参考与信息来源

  • IEEE 802.3标准(CRC-32定义)
  • Xilinx UG901 (Vivado Synthesis Guide)
  • 在线CRC计算器:https://crccalc.com
  • pycrc工具:https://pycrc.org
  • 《Verilog HDL高级数字设计》Michael D. Ciletti著

技术附录

术语表

  • 奇偶校验(Parity Check):通过额外位使数据中1的总数为奇数或偶数。
  • CRC(循环冗余校验):基于多项式除法的检错码。
  • LFSR(线性反馈移位寄存器):用于实现CRC的移位寄存器结构。
  • WNS(最差负时序裕量):时序分析中路径的最差裕量,应为正。

检查清单

  • □ 奇偶校验模块使用归约运算符
  • □ CRC模块复位后初始化为0x00
  • □ 仿真结果与在线计算器一致
  • □ 综合无警告(WARNING: [Synth 8-XXXX])
  • □ 时序约束正确,WNS≥0

关键约束速查

# 时钟约束
create_clock -period 10 [get_ports clk]
# 异步复位约束(可选)
set_false_path -from [get_ports rst_n]
分类
技术分享
标签
CRC校验Verilog奇偶校验
浏览 60
分享:

相关推荐

同频道 · 相近分类

暂无相关推荐

作者

二牛学FPGA查看主页

同分类阅读

文章

延伸阅读与实操

  • 文章 + 课程联动深度文章常对应体系课章节,可一键选课。
  • 学习产出可参考笔记与作业案例在学习产出广场持续更新。

探索全站