当前位置: 首页 > 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.jsqmd.com/news/882274/

相关文章:

  • common lisp 张量,矩阵计算库介绍
  • 苏州相城区宠物基地口碑推荐榜单一览 - 品牌排行榜
  • 保姆级教程:在Ubuntu20.04上为ROS2机器人项目配置CUDA11.3与TensorRT推理环境
  • SubCube稀疏注意力架构的优势是什么
  • PHP无参RCE
  • 医疗物联网异常检测:八种机器学习算法实战对比与选型指南
  • Armv9 SME指令集:矩阵运算加速原理与优化实践
  • 量子生成模型:原理、优势与应用场景解析
  • 终极指南:3种简单方法快速重置JetBrains IDE试用期
  • 大麦网抢票神器终极指南:告别黄牛票的Python自动化解决方案
  • ARM ETE协议异常处理与指令追踪技术解析
  • 3分钟快速修复:洛雪音乐六音音源终极解决方案
  • 增强采样与力匹配结合:高效构建高精度粗粒化分子动力学模型
  • 3分钟快速修复洛雪音乐播放问题:六音音源完整指南
  • 音频输入系统——第二周
  • 直接去偏机器学习:用Bregman散度统一因果推断与协变量平衡
  • 基于CNN的遥感影像土地利用分类:从原理到斐济城市扩张监测实践
  • JMeter压测8大实战陷阱:从线程模型到SLA验证
  • 嘉兴GEO优化公司2026年度深度评测选型指南 - 品牌报告
  • 卷积神经网络(CNN)与深度学习视觉应用综述
  • 我用 GPT-5.5 跑了一周行政工作:会议纪要、邮件整理,到底能省多少时间?
  • Windows Audio服务启动失败?除了疑难解答,你还需要检查这些容易被忽略的设置
  • 机器学习优化活性粒子信息引擎:突破热力学极限的非平衡控制
  • 苏州评价高的宠物基地口碑推荐榜单 - 品牌排行榜
  • 基于BERT与LSTM的抽取式新闻摘要实战:从原理到实现
  • BetterJoy:让Switch手柄在PC上完美工作的终极适配工具
  • 2024终极指南:如何用微信红包助手快速抢到所有红包
  • Python Pickle安全新方案:基于源码分析的机器学习模型安全加载实践
  • 数据集上新:柬埔寨环境健康入户调查
  • DownKyi终极指南:5步轻松下载B站高清视频的完整解决方案