0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

聊聊例化寄存器型的RTL编码设计

jf_GctfwYN7 来源:IC修真院 2023-11-10 17:28 次阅读

这篇文章来整体的聊一下个人理解的例化寄存器型的RTL编码风格。在脱离实验室氛围开始在公司芯片设计代码的时候,就发现公司里代码规范里明确表明:

1.避免always @*语句;

2.避免always时序语句;

这让我幼小的心灵备受打击,不用always怎么怎么写RTL呢?当然了写着写着也就习惯了。避免always @*这个咱们已经理解用意了,主要是避免X态问题被掩盖。那么避免always时序语句是为什么?又应该如何实操呢? 要避免always时序语句其实也很简单,自然就是例化dff了呀,根据接口和特性可以划分归类一下有哪几种dff我们可能会用得到:

1.是否需要复位

2.是否需要使能

3.是否需要校验

暂时排除第三种校验情况稍后再聊,根据前两个分类我们会得到以下的dff模块:

1.moon_dffre

2.moon_dffr

3.moon_dffe

4.moon_dff

这个前缀就是做一下标志随便加就可以。dff例化的风格怎么取代always时序呢,以下面这段代码为例:



reg [7:0]power; always @(posedge clk or negedge rst_n)begin if(!rst_n) power <= 8'b0; else if(case0) power <= case0_data; else if(case1) power <= case1_data; else if(case2) power <= power + 1'b1; end 以dff风格写的话就是下面这样:


//信号声明 wire [7:0]power_d; wire [7:0]power_q; wire power_en; //组合逻辑 assign power_en = case0 || case1 || case2; assign power_d = case0 ? case0_data : case1 ? case1_data : power_q + 1'b1; //时序逻辑 moon_dffre #(.WD(8)) u_power_dff(.clk(clk), .rst_n(rst_n), .d(power_d), .en(power_en), .q(power_q)); 这两种代码风格哪种好呢?对于优秀的编码者这两种是没有优劣之分的。不过对于我这种入门级选手以及交付来说,选用dff例化风格的代码还是有收益的:

1.能够规避不合理的代码习惯。最典型的就是时序逻辑中的clk_gating问题。想要综合工具自动插入门控的话,那么always块中就尽量不要有else分支(或者else分支是非阻塞赋值给自身),如果else中对信号赋常值了那么门控就插不进去,影响整个芯片的功耗。那么如果自己来写always块粗心大意了的话就可能出问题,且这个事完全靠个人意识了(当然工具可以查gating比例)。如果采用例化dff的方式,寄存器的实现方式就是统一的,只要dff模块写的合理那么无论如何调用都不会出这个问题。

2.便于X态检查。如同之前文章中所述的,if-else会掩盖X态问题,而如果我们希望对X态进行检查那么就可以统一在dff模块内来完成。

3.便于集中操作。假如某天突然有一个需求,要求所有的寄存器都加入校验逻辑,那么如果是always块怎么处理比较快速呢?需要把所有寄存器的值送入一个模块,然后连出一根error线。dff模块呢可以在模块内加入逻辑,例化时把error接出来||在一起。还是那句话,这两种方式难说好坏,dff例化型编码倒是可以从底层保证所有例化的寄存器都加入了校验逻辑(引出的工作还是得自己来的)。

4.便于全局替换。还是刚刚那个例子,加入校验逻辑,只需要全局把moon_dffre替换为moon_dffre_chk就可以了。

5.逻辑和互联更加清晰,更接近于底层电路实现对工具友好。同时我的习惯是用xx_d、xx_q、xx_en来命名信号,那么在写逻辑时,代码中用到了xx_q我就会非常放心因为这意味着该信号的时序极好,写习惯了对于时序路径的把握也有所提升。

6.有利于降低复位比例,利于功耗控制。dff例化风格编码时,组合逻辑和时序逻辑是分开写的,在每一个时序逻辑处都面临一个模块选型的问题,这个时候就需要分析这个寄存器是不是需要复位,如果不需要就选用moon_dffe型好了。而always块写法组合逻辑和时序逻辑是在一处写,精力很容易投在if-else的逻辑上,复位很多时候就顺手写了,后面还得艰难的降复位比例。

7.便于脚本工具集中处理,对,说的就是auto_dff哈哈。 最后一点,dff例化风格的代码天然的会分成信号声明、组合逻辑、时序逻辑三个部分,因此你可以选择这样组织代码:

//寄存器1 ...声明... ...逻辑... ...例化... //寄存器2 ...声明... ...逻辑... ...例化... 也可以很轻易的把三个区域分开:



...声明所有信号... ... ...例化所有寄存器... ... ...完成所有逻辑... ... 那么这个收益是什么呢?这样编码形式和风格容易写出美感,毕竟好看才是编码第一要务! 好的,dff编码风格的收益部分就写完了,接下来进行实操部分,各种dff模块应该怎么写呢?从最典型的moon_dffre写起吧。dffre顾名思义就是有复位有使能,内部根据使能进行赋值:


odulemodule moon_dffre #( parameter WD = 1, parameter VE = {WD{1'b0}}) ( input clk, input rst_n, input [DW -1:0]d, input en, output reg[DW -1:0]q ); always @(posedge clk or negedge rst_n)begin if(!rst_n) q <= VE; else if(en) q <= d; end endmodule 两个参数分别是寄存器的位宽和复位值。那么如果在模块内加入关于X态的校验,可以增加如下的代码(示意):


`ifdef ASSERT_ON property chk_en_xz(); @(posedge clk) disable iff(~rst_n) ~$isunknown(en); endproperty property chk_d_xz(); @(posedge clk) disable iff(~rst_n) en |-> ~$isunknown(d); endproperty assert_chk_en_xz: assert property(chk_en_xz()) else $assertoff(0, assert_chk_en_xz); assert_chk_d_xz: assert property(chk_d_xz()) else $assertoff(0, assert_chk_d_xz); `endif 这样一来,X态检查的问题就融在底层模块中了。顺着这个思路,另外几种dff的编码也很简单,moon_dffe:


module moon_dffe #( parameter WD = 1) ( input clk, input [DW -1:0]d, input en, output reg[DW -1:0]q ); always @(posedge clk)begin if(en) q <= d; end `ifdef ASSERT_ON property chk_en_xz(); @(posedge clk) disable iff(~rst_n) ~$isunknown(en); endproperty property chk_d_xz(); @(posedge clk) disable iff(~rst_n) en |-> ~$isunknown(d); endproperty assert_chk_en_xz: assert property(chk_en_xz()) else $assertoff(0, assert_chk_en_xz); assert_chk_d_xz: assert property(chk_d_xz()) else $assertoff(0, assert_chk_d_xz); `endif endmodule moon_dffr没有使能其实就没有必要检查什么X态的事了:


module moon_dffr #( parameter WD = 1, parameter VE = {WD{1'b0}}) ( input clk, input rst_n, input [DW -1:0]d, output reg[DW -1:0]q ); always @(posedge clk or negedge rst_n)begin q <= d; end endmodule 最最古朴的自然还是moon_dff:


module moon_dffr #( parameter WD = 1, parameter VE = {WD{1'b0}}) ( input clk, input rst_n, input [DW -1:0]d, output reg[DW -1:0]q ); always @(posedge clk)begin q <= d; end endmodule 基础版本的寄存器这四种就完全够用了。那么如果有需求在寄存器中加入校验,比如说加入奇偶校验,又该如何编码呢?这就需要一个单独的寄存器,当数据写入时同步写入校验位,之后每拍检查是否发生数据篡改:


module moon_dffre_chk #( parameter WD = 1, parameter VE = {WD{1'b0}}) ( input clk, input rst_n, input [DW -1:0]d, input en, output reg[DW -1:0]q, output e ); always @(posedge clk or negedge rst_n)begin if(!rst_n) q <= VE; else if(en) q <= d; end reg err_q; wire err_d = ^d; always @(posedge clk or negedge rst_n)begin if(!rst_n) err_q <= ^VE; else if(en) err_q <= err_d; end assign e = (err_q != ^q); `ifdef ASSERT_ON property chk_en_xz(); @(posedge clk) disable iff(~rst_n) ~$isunknown(en); endproperty property chk_d_xz(); @(posedge clk) disable iff(~rst_n) en |-> ~$isunknown(d); endproperty assert_chk_en_xz: assert property(chk_en_xz()) else $assertoff(0, assert_chk_en_xz); assert_chk_d_xz: assert property(chk_d_xz()) else $assertoff(0, assert_chk_d_xz); `endif endmodule 差不多啦,收工。

编辑:黄飞

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 寄存器
    +关注

    关注

    30

    文章

    5037

    浏览量

    117764
  • 芯片设计
    +关注

    关注

    15

    文章

    900

    浏览量

    54420
  • RTL
    RTL
    +关注

    关注

    1

    文章

    377

    浏览量

    59076
  • 代码
    +关注

    关注

    30

    文章

    4556

    浏览量

    66814
  • 时序逻辑
    +关注

    关注

    0

    文章

    37

    浏览量

    9100

原文标题:IC设计笔记 | 论RTL中always语法的消失术

文章出处:【微信号:IC修真院,微信公众号:IC修真院】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    ARM开发中几个常见的寄存器详解

    笔者今天来聊聊对于ARM几个特殊寄存器的理解,FP、SP和LR。
    发表于 11-22 09:02 3072次阅读

    聊聊寄存器被优化的2种情况

    在项目初期,在使用FPGA工具quartus或者vivado生成版本烧入开发板进行调试时(DC开启优化选项后同样会优化掉寄存器),我们有时会发现部分寄存器被优化掉了,今天简单聊聊被优化的几种情况。
    的头像 发表于 09-08 15:09 1307次阅读
    <b class='flag-5'>聊聊</b><b class='flag-5'>寄存器</b>被优化的2种情况

    有偿求助:RTL8365MB/RTL8363SB 寄存器问题

    内容:RTL8365MB/RTL8363SBdatasheet上写到可以通过寄存器配置GMAC的工作模式为GMII/RGMII/MII,但是datasheet中并没有相关的寄存器描述。
    发表于 08-30 09:53

    如何构建UVM寄存器模型并将寄存器模型集成到验证环境中

    进行多次。03 集成到验证环境如果只是简单把寄存器模型集成到验证环境,那么只要寄存器模型
    发表于 09-23 14:29

    寄存器与移位寄存器

    寄存器与移位寄存器 寄存器是用来寄存数码的逻辑部件,所以必须具备接收和寄存数码的功能。任何一种触发器都可以构成
    发表于 03-12 15:19 59次下载

    寄存器,寄存器是什么意思

    寄存器,寄存器是什么意思 寄存器定义  寄存器是中央处理器内的组成部分。寄存器是有限存贮容量的高速存贮部件,它们可用
    发表于 03-08 14:26 2.1w次阅读

    数据寄存器,数据寄存器是什么意思

    数据寄存器,数据寄存器是什么意思 数据寄存器数据寄存器包括累加器AX、基址寄存器BX、计数寄存器
    发表于 03-08 14:38 1.2w次阅读

    寄存器与移位寄存器

    寄存器与移位寄存器:介绍寄存器原理和移位寄存器的原理及实现。
    发表于 05-20 11:47 0次下载

    FPGA之软核演练篇:影子寄存器

    ARM核是一个非常紧凑的设计,影子寄存器的引入就是这种设计的表现。通过引入影子寄存器,指令可以重复使用相同的寄存器编码,但是在不同模式下,这些编码
    的头像 发表于 12-09 07:03 1516次阅读
    FPGA之软核演练篇:影子<b class='flag-5'>寄存器</b>组

    五个广泛使用的特殊寄存器

      下一步是学习如何在 IP-XACT 或 SystemRDL 中定义这些特殊寄存器。还需要学习如何在 RTL 中对其进行编码,并创建 UVM 寄存器模型并完成 UVM 测试平台以进行
    的头像 发表于 06-08 09:55 3737次阅读
    五个广泛使用的特殊<b class='flag-5'>寄存器</b>

    ARM通用寄存器及状态寄存器详解

    笔者来聊聊ARM通用寄存器以及状态寄存器的认识与理解。
    的头像 发表于 01-06 14:58 4918次阅读

    RAL寄存器模型操作图鉴

    寄存器模型操作,指的是通过寄存器模型对RTL寄存器进行读写访问,或者同步寄存器模型与RTL
    的头像 发表于 05-17 09:01 561次阅读
    RAL<b class='flag-5'>寄存器</b>模型操作图鉴

    RAL寄存器模型操作指南

    寄存器模型操作,指的是通过寄存器模型对RTL寄存器进行读写访问,或者同步寄存器模型与RTL
    的头像 发表于 07-12 09:37 705次阅读
    RAL<b class='flag-5'>寄存器</b>模型操作指南

    寄存器是什么 掌握使用寄存器做设计需要注意的事项

    既然RTL是以寄存器行为为基础,那么就必须先了解寄存器是什么,并且掌握使用寄存器做设计需要注意的事项。
    的头像 发表于 07-13 15:38 884次阅读
    <b class='flag-5'>寄存器</b>是什么 掌握使用<b class='flag-5'>寄存器</b>做设计需要注意的事项

    浅谈寄存器被优化的原因

    在项目初期,在使用FPGA工具quartus或者vivado生成版本烧入开发板进行调试时(DC开启优化选项后同样会优化掉寄存器),我们有时会发现部分寄存器被优化掉了,今天简单聊聊被优化的几种情况。
    的头像 发表于 09-26 09:47 538次阅读
    浅谈<b class='flag-5'>寄存器</b>被优化的原因