2-1VerilogHDL可综合描述原则,常见语法描述对应的硬件电路结构

逻辑综合

逻辑综合是ASIC半定制设计流程的一个阶段,用于将基于HDL的行为描述(RTL级层次)转化和优化为纯粹的结构描述(门级网表)

全定制设计:设计在电路级(晶体管级)进行,版图中每个器件和连线都是人工设计的,以期获得最小的芯片尺寸和最佳性能(速度、功耗)

  • 是一种以人工设计为主的方法,EDA自动化程度低,设计时间耗时、麻烦;一般只用版图编辑工具,进行版图编辑、DRC/ERC检查和模拟验证
  • 与IC工艺相关,可移植性、可重用性差
  • 全定制设计需要经验丰富的专业工程师,这样的全定制的设计效果才可能好于半定制,设计成本高。
  • 只有当现有的单元库满足不了要求,不计上市时间/成本压力时才考虑

半定制设计:是一种约束性设计方式,能简化设计/缩短设计周期,降低设计成本,提高设计正确率,按照逻辑实现方式的不同,可以分为门阵列法、标准单元法和可编程逻辑电路法

  • 设计调用预先已设计好的大小不一的标准单元完成,这些标准单元统称为标准单元库,一般是厂家预先为指定工艺生成逻辑门一级的设计实体
  • 单元库是人工全定制优化设计,已通过功能/性能的模拟和验证
  • 单元库通常与某一工艺对应,包含了电路单元在各种描述层次属性的一组数据
  • 设计人员不必关心低层次电路结构,可以在更高抽象层次设计电路的功能(行为级),由EDA工具自动综合生成网表和版图数据
  • 设计与工艺不相关,提高了设计可移植、可重用性,设计效率高
  • 与全定制相比,一般面积、功耗会稍大
  • EDA自动化程度高,大幅缩短了复杂数字IC的设计时间,降低了成本

综合的过程是:在Foundry厂家给出的标准单元库和设计人员给出的设计约束的前提下,将一个高级HDL设计描述转化为优化过的门级网表,并把优化的门级网表映射成由标准库单元组成的等效电路结构,输出门级网表文件
在这里插入图片描述

VerilogHDL高质量书写

VerilogHDL的基本功能之一就是描述可综合的硬件电路,但并不是所有的关键字都可以综合,有四个关键字可以综合为硬件电路 ,分别为alwaysif-elsecaseassign,其他很多关键字都是不可综合的,比如说fork-joinwhile,这些不可综合的关键字一般用于书写testbench

If-else相关语句的硬件结构映射及优化

If-else的硬件结构及优化

if-else映射的硬件结构为多路选择器

always @* begin
    if (Aflag == 1'b1) begin
        outData = A + B;
    end
    else begin
        outData = C + D;
    end
end

上述代码等价于下面的硬件电路

请添加图片描述

对上述代码进行如下的改写,可以减小电路的面积

reg [3:0] op1, op2;

always @* begin
    if (Aflag == 1'b1) begin
        op1 = A;
        op2 = B;
    end
    else begin
        op1 = C;
        op2 = D;
    end
end

always @* begin
    outData = op1 + op2;
end

其硬件电路为

请添加图片描述

该结构减少了一个加法器,增加了一个MUX,通常来说加法器的面积更大,因此改写后的代码可以生成更小面积的电路;但是改写电路的控制通道的传播延迟更大(一个MUX和一个加法器),如果控制信号到来的延迟比较晚,那么改写电路的性能会更差。因此需要根据输入约束,来选择“先加后选”还是“先选后加”。

具有优先级的判断结构

多条if语句可以“级联”,以执行多布尔条件并建立优先级,如下所示

always @(sel or A or B or C or D) begin
    Z = 4'b0;
    if (sel[0] == 1'b1) begin
        // 最高优先级
        Z = A;
    end
    else if (sel[1] == 1'b1) begin
        Z = B;
    end
    else if (sel[2] == 1'b1) begin
        Z = C;
    end
    else if (sel[3] == 1'b1) begin
        // 最低优先级
        Z = D;
    end
end

该代码对应的硬件结构如下所示

请添加图片描述

下面的代码也可以建立优先级。

always @(sel or A or B or C or D) begin
    Z = 4'b0;
    // 最低优先级
    if (sel[0] == 1'b1) begin
        Z = A;
    end
    if (sel[1] == 1'b1) begin
        Z = B;
    end
    if (sel[2] == 1'b1) begin
        Z = C;
    end
    // 最高优先级
    if (sel[3] == 1'b1) begin
        Z = D;
    end
end

其对应的硬件结构如下所示

请添加图片描述

在某些设计中,有些信号要求先到达(如关键使能信号、选择信号等),而有些信号需要后到达(如慢速信号、有效时间较长的信号等),此时可以使用具有优先级的if结构,一般是最高优先级给最迟到达的关键信号

case相关语句的硬件结构映射及优化

相对于if语句只有两个分支而言,case语句是一种多分支语句,故case语句可用于描述多条件分支电路,如译码器、数据选择器、状态机及微处理器指令译码等。

always @(sel or A or B or C or D) begin
    case (sel)
        4'b0001: Z = A;
        4'b0010: Z = B;
        4'b0100: Z = C;
        4'b1000: Z = D;
        default: Z = 0;
    endcase
end

上面代码对应的硬件结构如下所示

请添加图片描述

case语句在经过综合器优化后,不一定会生成多路选择器

除了常规的case语句,还有两种变体casez和casex。

  1. 在casez语句中,认为表达式中的z值和?是无关值(即对应为无需匹配)

  2. 在casex语句中,认为表达式中的z,x值和?为无关值。

由于z和x可能出现在仿真中,我们更倾向于采用?

下面给出了casez的一个使用案例

always @*
    casez (r)
        4'b1???: y = 3'b100;
        4'b01??: y = 3'b011;
        4'b001?: y = 3'b010;
        4'b0001: y = 3'b001;
        4'b0000: y = 3'b000; // 这里可以使用default
    endcase

综合命令 full_case 与 parallel_case 有时会被用来优化逻辑,比如可以减少资源消耗和减少逻辑级数。但是,这两个命令的使用也是很危险的,极易造成综合结果与仿真结果的不匹配,引入bug。详情参考这篇文章当心 full_case 和 parallel_case - 知乎 (zhihu.com)

慎用锁存器

锁存器由电平触发,当使能信号有效时latch相当于通路,使能信号无效时latch保持输出状态。慎用latch的原因主要有以下几点:

  1. 不能异步复位,上电后处于不确定的状态
  2. latch会使静态时序分析变得非常复杂**(?)**
  3. latch容易产生毛刺,触发器则不易产生毛刺**(?)**

一般的设计规则是:在绝大多数设计中避免产生latch,latch最大的危害在于不能过滤毛刺,这对于下一级电路是极其危险的,所以可以使用D触发器的地方就不用latch

容易产生latch的途径:case和if中使用不完备的条件判断语句,或者信号的输出赋值不完整,如下面的代码所示

always @* begin
    if (a > b)
        gt = 1'b1;
    else if (a == b)
        eq = 1'b1;
end

上面的if语句会生成类似如下的硬件结构,可以看到存在latch

请添加图片描述

解决上述引入latch的方法有以下2种:

  1. 补足所有可能的条件,并确保组合逻辑always块中每个输出信号在各个条件下都有赋值,case语句可以使用default语句
  2. 在always块的起始部分,给每个变量赋默认值

修改后的代码如下所示

// 方法1
always @* begin
    if (a > b) begin
        gt = 1'b1;
    	eq = 1'b0;
    end
    else if (a == b) begin
        gt = 1'b1;
        eq = 1'b1;
    end
    else begin
        gt = 1'b0;
        eq = 1'b0;
    end
end

// 方法2
// 如果gt和eq之后未赋值,则认为是0
always @* begin
    gt = 1'b0; // gt的默认赋值
    eq = 1'b0; // eq的默认赋值
    if (a > b) begin
        gt = 1'b1;
    end
    else if (a == b) begin
        eq = 1'b1;
    end
end

方法1对应的硬件电路如下所示

请添加图片描述

方法2对应的硬件电路如下所示

请添加图片描述

always块的一般编码原则

当always块用于描述组合逻辑电路时,一定要确保always块的敏感信号列表完整,即必须包含该块所有的输入信号,其基本的语法格式有以下三种

  1. 如有两个或者两个以上的信号时:在Verilog-1995中,它们之间可以用关键字or来连接,如 always @(a or b or c)
  2. VerilogHDL 2001规范中,可以使用“,”来区分,如:always @(a, b, c)
  3. 在Verilog HDL 2001中,也可以用符号 alway @*

当always块用于描述组合逻辑电路时,如果存在不完整分支和不完整输出赋值,则可能引入latch

资源顺序重排

在设计电路的时候可以对资源进行重排,降低延迟。如下图所示,A信号到来比较晚,可以将它尽可能放在后面,从而尽可能隐藏其延迟。

请添加图片描述

少用 “: ?” 赋值语句

assign a = (b=1)? ((c && d) ? 1'b1:1'b0) : 1'b0;

上面的代码难以阅读,且多层嵌套后很难被综合器解释,尽量将逻辑运算放在always块中,assign更多用于信号连接

时序电路使用非阻塞赋值,组合逻辑电路使用阻塞赋值

同步复位与异步复位

建议分开异步逻辑与同步逻辑,避免综合时的问题,简化约束和编码难度

分开控制逻辑和存储器

建议控制逻辑和存储器逻辑分成独立的模块,便于高层的存储器模块的使用和便于重新描述为不同的存储器类型

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值