VerilogHDL可综合描述

一、VerilogHDL可综合概述

1.VerilogHDL基本功能之一是描述可综合的硬件电路。

  • HDL:Hardware Description Language,硬件描述语言。

  • HDL语言具备以下硬件设计的基本概念:

    • 互连(connectivity):wire型变量描述各个模块之间的端口与网线连接关系。

    • 并发(concurrency):可以有效地描述并行的硬件系统。

    • 时间(time):定义了绝对和相对的时间度量,可综合操作符具有物理延迟。

  • 软件语言并无上述硬件对象。

2.硬件描述语言描述的电路,最终将通过逻辑综合工具、布局布线工具实现为芯片。

  • 通常,只有四个关键字能够被综合为电路:always、if-else、case、assign

  • 除此以外,其他关键字都不可以被综合为硬件电路,比如:function、for、fork、join。这些不可综合的关键字用于书写testbench。

二、常见可综合语法与硬件的映射关系

1.if-else

  • 通常会被逻辑综合映射为具有优先级的多路选择器。

  • 每个if else语句就是一个2选1选择器。

  • 设计方法:根据设计目标(面积和延迟)进行设计:先“加”后“选”,先“选”后“加”

先加后选:控制通道延时较小。

数据通道延时:一个加法器和一个选择器。

控制通道延时:一个选择器。

电路面积:两个加法器+一个选择器。

在这里插入图片描述

先选后加:减少了一个加法器,减小了硬件的面积(加法器结构复杂,使用晶体管较多)。

数据通道延时:一个加法器和一个选择器。

控制通道延时:一个选择器和一个加法器。

电路面积:两个选择器+一个加法器

在这里插入图片描述

2.单if语句

第一级选择信号具有最高的优先级。在设计中尽量使用单if语句(if…else if…else…)描述多条件判断结构,更简单,不易出错。

module Mux(
input           [2:0]   sel,
input                   a,b,c,
output  reg             f
    );
always@(*)begin
    if(sel[0])
        f = a;
    else if(sel[1])
        f = b;
    else if(sel[2])
        f = c;
    else
        f = 0;//所有条件不符时f=0,不生成锁存器
end
endmodule

在这里插入图片描述

3.多if语句(if if if)

最后一级选择信号具有最高优先级。

module Mux(
input           [2:0]   sel,
output  reg             f
    );
reg a,b,c;
always@(*)begin
    f = 0;//所有条件不符时f=0,不生成锁存器
    if(sel[0])
        f = a;
    if(sel[1])
        f = b;
    if(sel[2])
        f = c;
end
endmodule

在这里插入图片描述

多if语句末尾不可加else,否则最后一个条件不满足时,无论其他的条件是否满足,结果会被else的结果覆盖。

若某些设计中,有些信号要求先到达(如关键便能信号、选择信号等),而有些信号需要后到达(如慢速信号、有效时间较长的信号等)。

设计方法:最高优先级给最迟到达的关键信号。

4.case语句

通常被映射为多路选择器,当条件互斥时是一种无优先级的判断结构。

与单if语句的区别是,case的条件一般互斥,但case的条件选项并不要求互斥。

//条件互斥的四选一数据选择器
module Selector(
input           [1:0]   sel,
input                   a,b,c,d,
output  reg             f
    );
always@(*)begin
    case (sel)
        2'b00: f = a;
        2'b01: f = b;
        2'b10: f = c;
        2'b11: f = d;
        default: f = 0;
    endcase
end
endmodule

在这里插入图片描述

case语句的条件选项不要求互斥,虽然条件选项并发比较,但执行效果为谁在前且条件为真谁被执行,当条件不互斥时则存在优先级,效果如下。

//条件不互斥的数据选择器
module Selector(
input           [1:0]   sel,
input                   a,b,c,d,
output  reg             f
    );
always@(*)begin
    case (sel)
        2'b00: f = a;
        2'b01: f = b;
        2'b01: f = c;//条件不互斥,且条件不完备
        2'b11: f = d;
        default: f = 0;
    endcase
end
endmodule

在这里插入图片描述

三、电路设计需要注意的基本事项

1.慎用latch

逻辑综合工具很难解释latch,因此,除非特殊用途,一般避免引入latch。

**锁存器(latch)😗*电平敏感型存储器。在组合逻辑中,存在某个信号需要保持不变时,就会生成锁存器。

慎用latch的原因:

  • 对毛刺不敏感,不能过滤毛刺,容易在电路中传播毛刺。

  • 没有时钟信号,将静态时序分析变得复杂。

锁存器产生的原因:

  • 组合逻辑生成锁存器的原因是逻辑中有信号需要保持不变,而组合逻辑不能有环路(即反馈),因而通过生成锁存器达到保持不变的目的,即组合逻辑中若存在某个信号需要保持不变就会生成锁存器

  • case、if else if语句不完备

  • always:赋值表达式右端引用了敏感电平列表中没有列出的信号,那么在综合时,将会为该没有列出的信号隐含地产生一个透明锁存器。

设计方法:

  • 掌握良好且正确的代码风格,使用完整的条件语句(if else、case中的default)且最后一个分支(else或default)不是自己赋值给自己。

    • case:使用default,一是可以赋值为x,x表示未知,在综合时可以避免产生锁存器。在仿真时是红线表示。二是赋值为确定的值(一般为0);这样产生一个默认的情况。

    • if:加上else,赋值,产生默认的情况

  • always:赋值表达式右边参与赋值的信号全部在敏感电平列表中列出,或者使用always@(*)。

  • full_case和parallel_case综合器指令:

    • 使用full_case:告诉综合器,当前case结构所列条件已完备,
    • 使用parallel_case:告诉DC,所有条件均互斥,且并行,无优先权

2.逻辑复制-均衡负载

在电路设计的过程中,如果某个电路的负载比较多,则可以通过逻辑复制,降低关键信号的扇出,进而降低该信号的传播延迟,提高电路性能。

在这里插入图片描述

3.资源共享-减小面积

  • 如果电路中存在较多的公共单元,也可以通过资源共享的方式,减小面积。

  • 一般来说,共享会导致性能下降。

在这里插入图片描述

4.资源顺序重拍-降低传播延时

在设计电路时,可以根据数据的延迟,对资源顺序进行重排,降低传播延迟。

如图所示,A信号到来比较晚,可以把它尽可能放到后面,隐藏其延迟。

在这里插入图片描述

5.尽可能使用always描述电路

  • 在代码书写过程中,尽可能使用always描述电路,assign仅仅用来连线。

  • 少用:? :这种形式,因为这种形式通常难以阅读,且多层嵌套后很难被综合器解释。

阶梯式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。这样哪一行哪一种情况没跑到会一目了然。

四、可综合风格对代码的要求

1. 完整的always敏感信号列表

  • 所有的组合逻辑或锁存的always结构必须有敏感信号列表。这个敏感信号列表必须包含所有的输入信号。综合过程将产生一个取决于除敏感列表中所有其它值的结构,它将可能在行为仿真和门级仿真见产生潜在的失配。

  • 可以采用always@(*)减少出错

2.每个always敏感信号列表对应一个时钟

  • 在综合过程中,每个Verilog always块敏感信号列表只能对应一个时钟。

  • 这是将每一个过程限制在单一寄存器类型的要求,有利于逻辑综合和静态时序分析。

3.不允许Wait声明和#delay声明。

  • Wait声明语句,不论是清楚还是含糊,都不能用于可综合设计。从RTL级转换到gate级的综合工具一般都不支持Wait声明和#delay声明,为了有效的综合,这些语句应该避免。

  • 在不需要进行综合的行为模块中,如测试模块、表示行为的虚拟器件模块中可以使用。

4.在时序电路中必须使用非阻塞赋值(<=),组合逻辑电路必须使用阻塞赋值(=)

  • 阻塞赋值:前面的语句在执行时将完全阻塞后面的语句,直到前面语句的赋值完成以后才会执行下一句的右边表达式计算,赋值时就进行数值更新。

  • 非阻塞赋值:前面语句的执行并不会阻塞后面语句的执行,数值更新在赋值完成后。

具体用法:

1、 时序逻辑,使用 “非阻塞赋值”
2、锁存器(latch)建模,使用 “非阻塞赋值”
3、组合逻辑,使用 “阻塞赋值”
4、当在同一个 always 块里面既为组合逻辑又为时序逻辑时,使用“非阻塞赋值”
5、组合逻辑输出时,为消除毛刺会在输出端加一个触发器,即使用非阻塞赋值
6、一个always块里,阻塞复制和非阻塞复制不可以混用

5.full_case和parallel_case 综合器指令

除电路结构设计本身外,还可以控制综合器,对电路结构进行指定 ,例如 full-case和parallel-Case 综合器指令。

full_case

在理论上使用case语句对于不符合条件选项的我们可以使用default,但是实际应用中可能存在没有default的情况存在。

以交通控制红绿灯为例,只有红、绿、黄三种情况,不会出现第四种,故使用2bit就可表示所有情况,但会多出一种情况,综合的时候就会产生latch。故可使用full-case告诉综合器,当前case结构所列条件已完备,从而消除latch。

也可以使用default,既然实际上不可能出现满足default条件的情况,那么使用了也不会导致系统输出失常,也保证不会出现latch

//会出现latch的情况
always@(*)
    case(sel) 
        2'b00:  y = a;  //红
        2'b01:  y = b;  //绿
        2'b10:  y = c;  //蓝
    endcase
endmodule

//不出现latch的情况
always@(*)
    case(sel) //synopsys full_case
        2'b00:  y = a;
        2'b01:  y = b;
        2'b10:  y = c;
    endcase
endmodule

//不出现latch的情况
always@(*)
    case(sel) 
        2'b00:  y = a;  //红
        2'b01:  y = b;  //绿
        2'b10:  y = c;  //蓝
        default: y = 0; //实际中不会出现此条件
    endcase
endmodule

parallel_case

如果分支条件不互斥、在综合过程中存在优先级。

always@(irq)begin
    {int2, intl, intO} = 3'b0;
    casez (irq)
        3'b1??:int2 = 1'b1;
        3'b?1?:int1 = 1'b1;
        3'b??1:int0 = 1'b1;
        //如果条件不互斥,则存在优先级
    endcase
end

使用parallel_case:告诉DC,所有条件均互斥,且并行,无优先权

always@(irq)begin
    {int2, intl, intO} = 3'b0;
    casez (irq)
        3'b1??:int2 = 1'b1;//synopsys parallel_case
        3'b?1?:int1 = 1'b1;
        3'b??1:int0 = 1'b1;
        //如果条件不互斥,则存在优先级
    endcase
end

6.分开异步逻辑与同步逻辑。

原因:避免综合和静态时序时碰到问题,简化约束和编码难度。

例外:不可应用于非综合模块中(例如:总线模块,总线监视器或是模拟模块)除非他们被设计来综合仿真。

7.分开控制逻辑和存储器

建议控制逻辑和存储器逻辑分成独立的模块。通常来说,存储器是用memory compiler生成的,其综合方式与RTL代码不同,所以混在一起,不利于综合,不利于很方便地更换工艺库和平台。

五、总结

牢记并理解可综合“四大法宝”所对应的硬件结构。写前,确认电路指标(性能还是面积),根据指标设计电路。硬件思维方式,代码不再是一行行的代码而是一块一块的硬件模块;对所需实现的硬件电路“胸有成竹”。

参考资料:

芯动力——硬件加速设计方法

Verilog HDL可综合描述(高质量Verilog书写)

单/多if与case条件分支语句

从底层结构开始学习FPGA----MUX多路选择器(Multiplexer)

数字电路基础:关于锁存器latch

Verilog 有什么奇技淫巧?

  • 26
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值