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

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

3天内不再提示

Verilog写法:组合逻辑+时序逻辑

FPGA之家 来源:FPGA之家 作者:FPGA之家 2022-07-07 09:37 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

奇技淫巧我不会,但我这有一些我工作后才学到的一些Verilog写法。
数字电路设计主要就是,选择器、全加器、比较器,几个常用逻辑门,再加个D触发器,电路基本都能实现了。写代码其实是个体力活,电路和时序图应该在设计阶段就已经到了你的文档里或在脑子里没来得及写出来。组合逻辑+时序逻辑

		assign或always@(*)always@(posedge clk or negedge rst_n)
有人说掌握Verilog 20%的语法就可以描述 90%以上的电路,说的对。

casez



		always @(*)begin casez(code) 8'b1???_???? : data[2:0] = 3'd7; 8'b01??_???? : data[2:0] = 3'd6; 8'b001?_???? : data[2:0] = 3'd5; 8'b0001_???? : data[2:0] = 3'd4; 8'b0000_1??? : data[2:0] = 3'd3; 8'b0000_01?? : data[2:0] = 3'd2; 8'b0000_001? : data[2:0] = 3'd1; 8'b0000_0001 : data[2:0] = 3'd0; default : data[2:0] = 3'd0; endcaseend这样的case有优先级选择,可综合,实际项目可以使用,不过我个人习惯上还是,有优先用if-else,没有直接用case。synopsys的EDA工具有关于full case与parallel case可以查看下面博客链接。https://blog.csdn.net/li_hu/article/details/10336511 

generate+for

合理使用generate+for循环可以提高编码效率,同样的赋值语句需要赋值多次。

		generate genvar i; for(i=0;i<16;i=i+1) begin: neg_data assign neg_data_out[i*DATA_WIDTH +:DATA_WIDTH] =  -data_in[i*DATA_WIDTH +:DATA_WIDTH] endendgenerate
同一个模块需要实例化多次

		generate  genvar i; for(i=0;i<16;i=i+1) begin: mult_12x12 DW02_mult #( .A_WIDTH(12), .B_WIDTH(12) ) u_DW02_mult0( .A(mult_a[i*12 +:12]), .B(mult_b[i*12 +:12]), .TC(1'b0), .PRODUCT(product[i*24 +:24]) ); endendgenerate
当然这样写debug会有一些困扰,Verdi会显示每一个generate块,选中对应的块,加进去的波形就会是对应的bit信号

generate if/case

做一些通用IP的方法,随便举个例子比如要做一个选择器通用IP,支持二选一,三选一,四选一。

		generate if(MUX_NUM == 0)begin : mux4_1 always@(*)begin case(sel[1:0]) 2'b00:data_out = data_in0; 2'b01:data_out = data_in1; 2'b10:data_out = data_in2; default:data_out = data_in3; endcase endend else if(MUX_NUM = 1) begin : mux3_1 always@(*)begin case(sel[1:0]) 2'b00:data_out = data_in0; 2'b01:data_out = data_in1; default:data_out = data_in2; endcase endend else begin : mux2_1 always@(*)begin case(sel[1:0]) 2'b00:data_out = data_in0; default:data_out = data_in1; endcase endend endgenerate
generate case可以写更多的分支

		generate case(MUX_NUM) 0:begin:mux_2 end 1:begin: mux_3 end 2:begin: mux_4 end default:begin end endcaseend endgenerate
调用的时候只需要

		mux #( .MUX_NUM(0))u_mux( ...);

参数化定义

模块化设计,功能模块的划分尽可能细,差别不大的代码通过参数化达到重复使用的目的。

		always @(*)begin case(sel) CASE0:data_out = data_in0; CASE1:data_out = data_in1; CASE2。。。 default:; endcase end
实例化

		mux #( .CASE0(8'd11), .CASE1(8'd44) ...)u_mux( ...);

移位操作

对于移位操作直接用位拼接

		assign data_shift[6:0] = data[4:0] << 2;assign data_shift[7:0] = data[4:0] << shift[1:0];
写成

		assign data_shift[6:0] = {data[4:0], 2'b0};always @(*)begin case(shift[1:0]) 2'b00: data_shift[7:0] = {3'b0, data[4:0]}; 2'b01: data_shift[7:0] = {2'b0, data[4:0], 1'b0}; 2'b10: data_shift[7:0] = {1'b0, data[4:0], 2'b0}; default:data_shift[7:0] = {data[4:0], 3'b0}; endcaseend
如果是有符号数,高位要补符号位。也就是算术移位。

		always @(*)begin case(shift[1:0]) 2'b00: data_shift[7:0] = {{3{data[4]}}, data[4:0]}; 2'b01: data_shift[7:0] = {{2{data[4]}}, data[4:0], 1'b0}; 2'b10: data_shift[7:0] = {data[4], data[4:0], 2'b0}; default:data_shift[7:0] = {data[4:0], 3'b0}; endcaseend
shift也可能是有符号数,正数左移,负数右移。右移方法同理。

$clog2系统函数

Verilog-2005引入了$clog2系统函数,为了方便计算数据位宽,避免位浪费。(这个是拿来凑字数的)

		parameter DATA_WIDTH = 4,parameter CNT_WIDTH = log2(DATA_WIDTH)parameter CNT_WIDTH = clog2(DATA_WIDTH-1)parameter CNT_WIDTH = $clog2(DATA_WIDTH) reg [DATA_WIDTH-1:0] data_r0; reg [CNT_WIDTH-1:0] cnt; //-------------------------------------------------------//以下两个函数任用一个//求2的对数函数function integer log2; input integer value; begin value = value-1; for (log2=0; value>0; log2=log2+1) value = value>>1; endendfunction //求2的对数函数function integer clogb2 (input integer bit_depth);begin for(clogb2=0; bit_depth>0; clogb2=clogb2+1) bit_depth = bit_depth>>1;endendfunction

对齐

tab键还是空格键?留言区说出你的故事。我把编辑器设置成tab自动替换成4个空格。 用空格对齐代码,提高代码观赏性。

		assign signal_b = signal_a;assign data_b = data_a;assign cs_en = 1'b1; assign signal_b = signal_a;assign data_b = data_a;assign cs_en = 1'b1;
第二种写法更美观,always块里面的语句也应该对齐。

命名

给模块起名字,给信号起名字,真的很难,但是不管怎样都不要用拼音,会遭人鄙视。是的,我见过!

阶梯式assign


		assign data_out[5:0] = data_vld0 ? data0[5:0] : data_vld1 ? data1[5:0] :  data_vld2 ? data2[5:0] :  data_vld3 ? data3[5:0] : 6'b0;
由于if-else和case不能传播不定态,有的EDA工具有X态传播选项,可以强行传播,但是并不是所有的EDA工具都有这个功能,所以有些书上建议都用组合逻辑用assign。 这种写法没什么问题,但是有一点,覆盖率不好收,如果一些情况没跑到需要一个个分析。覆盖率会把数据信号当作一个情况列出来,比如数据信号data没出现过0 的情况,实际上数据信号没出现0的情况是正常的,这就要你一个一个的exclude掉。 所以不要写很长的assign做选择器,有优先级用if-else,或根据具体情况用case。这样哪一行哪一种情况没跑到会一目了然。当然if中的条件太多,覆盖率也不好收,条件太多组合的情况多,分析起来繁琐。如果上述信号的vld不同时出现也可以采用这种写法,减少cell的使用数量。这样也是有覆盖率的问题,这只是一种特殊情况,很长的assign选择器尽量不要写。

		assign data_out[5:0] = ({6{data_vld0}} & data0[5:0]) | ({6{data_vld1}} & data1[5:0]) | ({6{data_vld2}} & data2[5:0]) | ({6{data_vld0}} & data3[5:0]);
关于X态传播,一定要注意,带有reset的寄存器面积和时序会稍微差一些,控制通路的寄存器必须带有复位,数据通路的寄存器可以不带复位,但是要注意使用时如果使用数据通路的数据去做了控制条件,就必须要复位,否则如果X态没有查出来,事情就大了。

布线太密的原因

寄存器位宽太大。

		reg [10000-1:0] data;
		这样写在功能上没什么问题,但是如果你之后有对这个数据做了很多逻辑,可能会造成后端布线太密,从后端的角度看到其实cell数量并不多,就是线比较密,比如说这个数据后面再放个选择器,或者输出给其他模块,就相当于一万根线连到很多地方,布线很紧张,如果时序有问题需要绕线,或者需要ECO,做成的可能性很小。
		尽量不要这样做逻辑,除非对面积没限制,要么最后只能改架构。
		第二个原因是负载太大。同一个信号在很多地方使用,布线也会变复杂,比如最常见的是参数信号,在很多模块都会有用到的情况,用寄存器复制的方法。

		always @(posedge clk or negedge rst_n)begin if(!rst_n)begin data_para0 <= 4'b0; data_para1 <= 4'b0; data_para2 <= 4'b0; end else begin data_para0 <= data_para; data_para1 <= data_para; data_para2 <= data_para;  endend
画俩图大概意思一下。这样每个寄存器的驱动变少。74509010-fd90-11ec-ba43-dac502259ad0.png745b09be-fd90-11ec-ba43-dac502259ad0.png

有网友提到这样子写被综合掉的概率也是很大。所以就只能在设计时尽量注意负载的问题。

加比选

面积:加法器 > 比较器 > 选择器乘法器本质上也是全加器。所以就有先选后比,先选后加,先选后乘。

		assign sum[4:0] = enable ? (data_a + data_b) : (data_c + data_d); assign add_a[3:0] = enable ? data_a : data_c;assign add_b[3:0] = enable ? data_b : data_d;assign sum[4:0] = add_a + add_b;

画个图意思一下。

7468a222-fd90-11ec-ba43-dac502259ad0.png747363b0-fd90-11ec-ba43-dac502259ad0.png

数据通路与控制通路

数据通路打拍可以不带复位,带着使能信号去打拍,减少信号翻转,减少功耗。保证数据用的时候不是X态, 组合逻辑路径是否需要插入pipeline,插入pipeline的位置需要注意。寄存器能少用就少用。 尽量不要用除法,首先除法器面积更大,除法也会有余数,余数是否需要保留就很麻烦。除以常数可以做成乘以定点常数的方法。 乘以常数用移位加,也可直接用*号。例如a * 2‘d3,工具会帮你优化成 a << 2’d1 + a。甚至可能优化得更好。(杠:不要过度依赖工具)。关于用移位加还是*号的问题,博主做过综合后的面积对比,相对来说,工具还是优化那么一点点。直接用 * 号吧。 尽量不要用减法,减法要考虑到减翻的问题,尽量用加法。

方案设计

方案最重要,一个好的方案往往事半功倍。 状态机设计要状态明确,一个状态尽量只做一件事情。状态机大法好。 做成IP化设计,功能分割尽量独立并可复用性,相同的功能用同一块IP,保证IP的没问题,最后像搭积木一样,搭建起数字系统。多积累些常用IP,常用的一些写法的代码。

审核编辑 :李倩


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

    关注

    31

    文章

    5588

    浏览量

    129053
  • 比较器
    +关注

    关注

    14

    文章

    1886

    浏览量

    111422
  • Verilog
    +关注

    关注

    30

    文章

    1370

    浏览量

    114129

原文标题:Verilog有什么奇技淫巧?

文章出处:【微信号:zhuyandz,微信公众号:FPGA之家】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    长晶科技逻辑芯片产品矩阵介绍

    逻辑IC是用于实现基本逻辑运算和复合逻辑运算的集成电路, 广泛应用于各种电子设备和系统中,成为现代电子设备智能化、高效化的关键所在。
    的头像 发表于 11-04 17:47 1055次阅读
    长晶科技<b class='flag-5'>逻辑</b>芯片产品矩阵介绍

    vivado时序分析相关经验

    存在不满足时序要求的逻辑级数。逻辑级数过多一般可以通过插入寄存器打拍子,分割冗长的组合逻辑。 线延时较长时,一般是因为扇出较大。 ”repo
    发表于 10-30 06:58

    MDD 逻辑IC的逻辑电平不兼容问题与解决方案

    在现代电子系统中,MDD辰达半导体逻辑IC(集成电路)扮演着至关重要的角色,广泛应用于数据处理、时序控制、信号转换等各类电路中。随着技术的进步,不同逻辑系列的IC(如TTL、CMOS、BiCMOS等
    的头像 发表于 10-29 09:39 159次阅读
    MDD <b class='flag-5'>逻辑</b>IC的<b class='flag-5'>逻辑</b>电平不兼容问题与解决方案

    时序约束问题的解决办法

    在使用vivado对 Verilog 代码进行综合后,点击“SYNTHESIS”下的“Report Timing Summary”,可以查看综合后的时序报告,查看 Setup Time 和 Hold
    发表于 10-24 09:55

    咨询符合国标GB/T 4728.12-2022的逻辑门电路设计软件

    不正确呀。 咨询 1、开源免费的软件,能够绘制符合国家标准GB/T 4728.12-2022的逻辑门电路,绘制和验证简单的逻辑电路,最好提供74LS系列等常用的芯片,以及基本门电路芯片连接、组合等功能
    发表于 09-09 09:46

    如何选择合适的逻辑芯片

    电工们可能对放大器头疼、可能对ADC/DAC应用发怵,但是对于小逻辑芯片,那就轻车熟路、信手拿来对着真值表就可以放心使用了。但是这小小的逻辑芯片,却演绎着控制系统的大世界。
    的头像 发表于 07-14 17:38 989次阅读
    如何选择合适的<b class='flag-5'>逻辑</b>芯片

    数字电路—22、时序逻辑电路

    时序电路的逻辑功能可用逻辑表达式、状态表、卡诺图、状态图、时序图和逻辑图6种方式表示,这些表示方法在本质上是相同的,可以互相转换
    发表于 03-26 15:03

    CMOS逻辑IC是如何构成的

    电子设备正常运转离不开“逻辑”的精密驱动。例如,当我们在手机上滑动屏幕时,背后就有无数个CMOS逻辑电路在默默工作,它们通过复杂的逻辑运算,将我们的触摸信号转化为手机能够理解的指令,从而实现各种功能。
    的头像 发表于 03-10 10:33 937次阅读
    CMOS<b class='flag-5'>逻辑</b>IC是如何构成的

    根据波形图编写Verilog代码

    根据下面的时序图实现这个组合逻辑电路。
    的头像 发表于 02-17 14:38 927次阅读
    根据波形图编写<b class='flag-5'>Verilog</b>代码

    逻辑板升级工具

    逻辑板升级工具
    发表于 02-10 13:50 0次下载

    解密逻辑单元与CoreScore得分的关系

    FPGA 通过查找表 (LUT) 实现逻辑功能。这些 LUT 类似于真值表或卡诺图 (Karnaugh map),FPGA 可以通过组合多个 LUT ,来实现几乎任何你所需的逻辑功能。
    的头像 发表于 02-06 15:06 694次阅读
    解密<b class='flag-5'>逻辑</b>单元与CoreScore得分的关系

    复合的逻辑运算

    符合逻辑运算
    的头像 发表于 01-16 09:10 557次阅读
    复合的<b class='flag-5'>逻辑</b>运算

    Verilog 与 ASIC 设计的关系 Verilog 代码优化技巧

    Circuit,专用集成电路)设计是一个复杂的过程,涉及到逻辑设计、综合、布局布线、物理验证等多个环节。在这个过程中,Verilog被用来描述数字电路的行为和结构,进而实现ASIC的设计。 具体来说
    的头像 发表于 12-17 09:52 1438次阅读

    如何使用 Verilog 进行数字电路设计

    首先,你需要清楚地了解你的数字电路需要实现什么功能。这可能包括输入输出的数量、数据宽度、时钟频率、时序要求等。明确的需求是设计成功的关键。 2. 设计逻辑电路 在明确了需求之后,你需要设计逻辑电路。这可以通过手绘
    的头像 发表于 12-17 09:47 1753次阅读

    Verilog与VHDL的比较 Verilog HDL编程技巧

    :由于其类似于 C 语言的语法,Verilog 代码通常更易于阅读和维护,尤其是在处理复杂逻辑时。 VHDL :VHDL 的正式性和丰富
    的头像 发表于 12-17 09:44 2688次阅读