当前位置: 首页 > news >正文

【Verilog代码规范引起的国产安路编译器不能识别寄存器】

Verilog代码规范引起的编译器不能识别寄存器

  • 问题简介
  • 问题描述
    • Xilinx Vivado编译器
    • 国产安路TD_5.6.5_Release_119222编译器
    • 解决办法
  • 总结

问题简介

对不需要复位的寄存器放入了异步复位的always块中,不同编译器所生成的RTL硬件电路是不一样的。有的编译器会将其识别为不复位寄存器,而有的却将其视为输入到输出的组合逻辑;本文就这个问题进行阐述,最后给广大Verilog码农们一个建议(或许如今大家早已不在手撸代码,但这里算是给未来的自己一个回忆吧😀)。

问题描述

笔者目前使用了xilinx vivado编译器、国产安路编译器TD_5.6.5_Release_119222,因此针对这两个编译器对同一个verilog模块代码进行生成RTL视图做对比。

Xilinx Vivado编译器

现有一段CRC16CCITT-False Verilog代码中,该模块输入8bit数据,经过一个时钟周期产生出CRC16CCITT-FalseCRC结果;由于输入带有一个数据有效信号,因此输出也需要带一个CRC校验结果有效的有效信号,具体代码如下:

`timescale 1ns / 1ps `default_nettype none `unconnected_drive pull0 //* 模块被例化未被驱动的IO直接驱动到GND module CRC16CCITT #( parameter INIT_BIT = 1'b1, parameter XOR_OUT_BIT = 1'b0, parameter IN_MOD = 1'b1, //*---- Data Input Mode (1 = Consecutive Data input 0 = Interval Data input) parameter REF_IN = "True", //*---- Data Reflect In ("True" = Reflect,"False" = No-Reflect) parameter REF_OUT = "True" //*---- Data Reflect Out("True" = Reflect,"False" = No-Reflect) )( input wire SysClk , input wire SysRst , input wire [07 : 00] iData , input wire iDataVali , output wire [15 : 00] oCrcDat , output wire oCrcDatVali ); //!--------------------------------------Reflect In--------------------------------------//! wire [07 : 00] RefDatIn; genvar i; generate for (i = 0;i < 8 ; i = i + 1 ) begin assign RefDatIn[i] = (REF_IN == "True") ? iData[7-i] : iData[i]; end endgenerate //!--------------------------------------------------------------------------------------//! //!--------------------------------------Reflect Out--------------------------------------//! reg [15 : 00] lfsr_q; reg [15 : 00] lfsr_c; reg CrcDatVali; wire [15 : 00] RefDatOut; wire [15 : 00] XorOutVal; wire [15 : 00] CrcResDat; assign oCrcDatVali = CrcDatVali; generate for (i = 0;i < 16 ;i = i + 1 ) begin assign RefDatOut[i] = lfsr_q[15-i] ; end endgenerate assign CrcResDat = (REF_OUT == "True") ? RefDatOut : lfsr_q; assign XorOutVal = XOR_OUT_BIT ? {16{1'b1}} : {16{1'b0}}; assign oCrcDat = CrcResDat ^ XorOutVal; //!---------------------------------------------------------------------------------------//! //!--------------------------------------CRC Cal--------------------------------------//! wire LfsrRstEn; assign LfsrRstEn = IN_MOD ? ~iDataVali : 1'b0; //*---- 16bit Input always @(*) begin lfsr_c[00] = lfsr_q[08] ^ lfsr_q[12] ^ RefDatIn[00] ^ RefDatIn[04]; lfsr_c[01] = lfsr_q[09] ^ lfsr_q[13] ^ RefDatIn[01] ^ RefDatIn[05]; lfsr_c[02] = lfsr_q[10] ^ lfsr_q[14] ^ RefDatIn[02] ^ RefDatIn[06]; lfsr_c[03] = lfsr_q[11] ^ lfsr_q[15] ^ RefDatIn[03] ^ RefDatIn[07]; lfsr_c[04] = lfsr_q[12] ^ RefDatIn[04]; lfsr_c[05] = lfsr_q[08] ^ lfsr_q[12] ^ lfsr_q[13] ^ RefDatIn[00] ^ RefDatIn[04] ^ RefDatIn[05]; lfsr_c[06] = lfsr_q[09] ^ lfsr_q[13] ^ lfsr_q[14] ^ RefDatIn[01] ^ RefDatIn[05] ^ RefDatIn[06]; lfsr_c[07] = lfsr_q[10] ^ lfsr_q[14] ^ lfsr_q[15] ^ RefDatIn[02] ^ RefDatIn[06] ^ RefDatIn[07]; lfsr_c[08] = lfsr_q[00] ^ lfsr_q[11] ^ lfsr_q[15] ^ RefDatIn[03] ^ RefDatIn[07]; lfsr_c[09] = lfsr_q[01] ^ lfsr_q[12] ^ RefDatIn[04]; lfsr_c[10] = lfsr_q[02] ^ lfsr_q[13] ^ RefDatIn[05]; lfsr_c[11] = lfsr_q[03] ^ lfsr_q[14] ^ RefDatIn[06]; lfsr_c[12] = lfsr_q[04] ^ lfsr_q[08] ^ lfsr_q[12] ^ lfsr_q[15] ^ RefDatIn[00] ^ RefDatIn[04] ^ RefDatIn[07]; lfsr_c[13] = lfsr_q[05] ^ lfsr_q[09] ^ lfsr_q[13] ^ RefDatIn[01] ^ RefDatIn[05]; lfsr_c[14] = lfsr_q[06] ^ lfsr_q[10] ^ lfsr_q[14] ^ RefDatIn[02] ^ RefDatIn[06]; lfsr_c[15] = lfsr_q[07] ^ lfsr_q[11] ^ lfsr_q[15] ^ RefDatIn[03] ^ RefDatIn[07]; end // always always @(posedge SysClk, posedge SysRst) begin CrcDatVali <= iDataVali; if(SysRst | (LfsrRstEn)) begin lfsr_q <= INIT_BIT ? {16{1'b1}} : {16{1'b0}};//*-----{16{1'b1}}; end else begin lfsr_q <= iDataVali ? lfsr_c : lfsr_q; end end // always //!----------------------------------------------------------------------------------//! endmodule `nounconnected_drive `default_nettype wire //!--------------------------------------End CRC16CCITT--------------------------------------

上述代码中oCrcDatVali为数据输入有效信号iDataVali延迟一个时钟周期的信号,Xilinx Vivado生成的RTL视图如图所示:

从图中可以看出Xilinx Vivado生成一个CrcDatVali的寄存器,且并没任何复位操作,与设计意图一致。

国产安路TD_5.6.5_Release_119222编译器

同样使用国产安路TD_5.6.5_Release_119222编译器对上述代码进行编译生成RTL视图,如图所示

从生成的RTL视图中可以看出编译器将输入的iDataVali经过了两个Buff,然后直接输出到了oCrcDatVali端口中,这与代码中需要进行一个时钟周期的意思完全不一致。
此外笔者也是再芯片上进行在线调试,发现iDataValioCrcDatVali信号没有一个时钟周期的延迟。就这个问题,折腾了一天才最终定位此处。

解决办法

在代码中,对不需要复位的寄存器单独放入一个没有异步复位信号的alwasy块中进行处理,因此上述代码变为

`timescale 1ns / 1ps `default_nettype none `unconnected_drive pull0 //* 模块被例化未被驱动的IO直接驱动到GND module CRC16CCITT #( parameter INIT_BIT = 1'b1, parameter XOR_OUT_BIT = 1'b0, parameter IN_MOD = 1'b1, //*---- Data Input Mode (1 = Consecutive Data input 0 = Interval Data input) parameter REF_IN = "True", //*---- Data Reflect In ("True" = Reflect,"False" = No-Reflect) parameter REF_OUT = "True" //*---- Data Reflect Out("True" = Reflect,"False" = No-Reflect) )( input wire SysClk , input wire SysRst , input wire [07 : 00] iData , input wire iDataVali , output wire [15 : 00] oCrcDat , output wire oCrcDatVali ); //!--------------------------------------Reflect In--------------------------------------//! wire [07 : 00] RefDatIn; genvar i; generate for (i = 0;i < 8 ; i = i + 1 ) begin assign RefDatIn[i] = (REF_IN == "True") ? iData[7-i] : iData[i]; end endgenerate //!--------------------------------------------------------------------------------------//! //!--------------------------------------Reflect Out--------------------------------------//! reg [15 : 00] lfsr_q; reg [15 : 00] lfsr_c; reg CrcDatVali; wire [15 : 00] RefDatOut; wire [15 : 00] XorOutVal; wire [15 : 00] CrcResDat; assign oCrcDatVali = CrcDatVali; generate for (i = 0;i < 16 ;i = i + 1 ) begin assign RefDatOut[i] = lfsr_q[15-i] ; end endgenerate assign CrcResDat = (REF_OUT == "True") ? RefDatOut : lfsr_q; assign XorOutVal = XOR_OUT_BIT ? {16{1'b1}} : {16{1'b0}}; assign oCrcDat = CrcResDat ^ XorOutVal; //!---------------------------------------------------------------------------------------//! //!--------------------------------------CRC Cal--------------------------------------//! wire LfsrRstEn; assign LfsrRstEn = IN_MOD ? ~iDataVali : 1'b0; //*---- 16bit Input always @(*) begin lfsr_c[00] = lfsr_q[08] ^ lfsr_q[12] ^ RefDatIn[00] ^ RefDatIn[04]; lfsr_c[01] = lfsr_q[09] ^ lfsr_q[13] ^ RefDatIn[01] ^ RefDatIn[05]; lfsr_c[02] = lfsr_q[10] ^ lfsr_q[14] ^ RefDatIn[02] ^ RefDatIn[06]; lfsr_c[03] = lfsr_q[11] ^ lfsr_q[15] ^ RefDatIn[03] ^ RefDatIn[07]; lfsr_c[04] = lfsr_q[12] ^ RefDatIn[04]; lfsr_c[05] = lfsr_q[08] ^ lfsr_q[12] ^ lfsr_q[13] ^ RefDatIn[00] ^ RefDatIn[04] ^ RefDatIn[05]; lfsr_c[06] = lfsr_q[09] ^ lfsr_q[13] ^ lfsr_q[14] ^ RefDatIn[01] ^ RefDatIn[05] ^ RefDatIn[06]; lfsr_c[07] = lfsr_q[10] ^ lfsr_q[14] ^ lfsr_q[15] ^ RefDatIn[02] ^ RefDatIn[06] ^ RefDatIn[07]; lfsr_c[08] = lfsr_q[00] ^ lfsr_q[11] ^ lfsr_q[15] ^ RefDatIn[03] ^ RefDatIn[07]; lfsr_c[09] = lfsr_q[01] ^ lfsr_q[12] ^ RefDatIn[04]; lfsr_c[10] = lfsr_q[02] ^ lfsr_q[13] ^ RefDatIn[05]; lfsr_c[11] = lfsr_q[03] ^ lfsr_q[14] ^ RefDatIn[06]; lfsr_c[12] = lfsr_q[04] ^ lfsr_q[08] ^ lfsr_q[12] ^ lfsr_q[15] ^ RefDatIn[00] ^ RefDatIn[04] ^ RefDatIn[07]; lfsr_c[13] = lfsr_q[05] ^ lfsr_q[09] ^ lfsr_q[13] ^ RefDatIn[01] ^ RefDatIn[05]; lfsr_c[14] = lfsr_q[06] ^ lfsr_q[10] ^ lfsr_q[14] ^ RefDatIn[02] ^ RefDatIn[06]; lfsr_c[15] = lfsr_q[07] ^ lfsr_q[11] ^ lfsr_q[15] ^ RefDatIn[03] ^ RefDatIn[07]; end // always always @(posedge SysClk) begin //*---- Not Reset CrcDatVali <= iDataVali; end always @(posedge SysClk, posedge SysRst) begin if(SysRst | (LfsrRstEn)) begin lfsr_q <= INIT_BIT ? {16{1'b1}} : {16{1'b0}};//*-----{16{1'b1}}; end else begin lfsr_q <= iDataVali ? lfsr_c : lfsr_q; end end // always //!----------------------------------------------------------------------------------//! endmodule `nounconnected_drive `default_nettype wire //!--------------------------------------End CRC16CCITT--------------------------------------

最后使用国产安路TD_5.6.5_Release_119222编译器对修改后的代码生成RTL如图所示

经过修改代码后,得到的RTL视图与代码设计思路一致,至此解决了输入与输出没有延时一个时钟周期问题。

总结

为了保证所设计的代码能在多平台运行,因此需要规范代码:


1、将不需要异步复位的寄存器放在一个没有任何复位信号的always块中
2、带有异步复位always块中所有信号都需要对其复位处理
3、尽量少用异步复位always块


在此呼吁国产安路加油!!!(修复该Bug)

http://www.zskr.cn/news/1376145.html

相关文章:

  • common lisp 张量,矩阵计算库介绍
  • git--github
  • 从NCM格式束缚到MP3音乐自由:3步解锁你的网易云音乐收藏
  • PHP无参RCE
  • 苏州相城区宠物基地口碑推荐榜单一览 - 品牌排行榜
  • 智慧树自动刷课插件:3步安装指南,彻底解放学习时间
  • 3分钟快速修复:洛雪音乐六音音源终极解决方案
  • ARM ETE协议异常处理与指令追踪技术解析
  • 增强采样与力匹配结合:高效构建高精度粗粒化分子动力学模型
  • 从人工标注到模型上线:一个多月搞定裂缝检测数据集的实战复盘(含YOLO/VOC格式)
  • 原码、反码、补码:概念解析与记忆方法
  • 我用 GPT-5.5 跑了一周行政工作:会议纪要、邮件整理,到底能省多少时间?
  • 3.RAG
  • 引力波透镜探测:参数偏移与似然比检验的统计框架与应用
  • 从CentOS迁移到openEuler?手把手教你在vSphere ESXi 7.0上搭建测试环境
  • 用信息架构拆解豪芬车载香薰官网
  • 2026年学习Java还有前景吗?如何看待2026Java程序员就业难现状?
  • 机器学习优化活性粒子信息引擎:突破热力学极限的非平衡控制
  • 基于BERT与LSTM的抽取式新闻摘要实战:从原理到实现
  • 深度学习与神经网络学习笔记 —— 卷积神经网络(CNN)基础
  • Week 1:机器学习入门与核心框架
  • GHelper终极指南:华硕笔记本轻量控制工具的专业使用教程
  • 别只盯着烘焙!深入理解Unity URP中反射球与屏幕空间反射的实战抉择与配置
  • Codex适配国产信创环境安装部署与技术适配全解析
  • 数据集上新:柬埔寨环境健康入户调查
  • 内存池仿Nginx C++实现
  • 基于CRISP-DM与HMM的国有企业内部威胁安全成熟度评估框架
  • 从安装到卸载:我在macOS Big Sur上使用雷蛇雷云2.0驱动的完整踩坑记录
  • Type-C接口水冷散热器
  • 2026照片去水印免费软件全攻略:一看就会的保姆级教程,赶紧收藏