在设计仿真激励文件时,为了满足和外部芯片接口的时序要求,经常会用到延时赋值语句,由于不同的延时赋值语句在仿真过程中行为不同,会产生不同的激励输 出,如果不认真区分不同表达式引起的差异,就可能产生错误的激励,无法保证仿真结果的正确,本文就是区分各种延时赋值语句的差异,并给出比较结果。

1:阻塞式左延时赋值语句
举例说明如下

module adder_t1 (co, sum, a, b, ci);
output co;
output [3:0] sum;
input [3:0] a, b;
input ci;
reg co;
reg [3:0] sum;
always @(a or b or ci)
#12 {co, sum} = a + b + ci; // 在15ns时a发生变化,启动该块,但是等到27ns时才执行后面的语句,所以是最新的结果
endmodule

分析:上面例子是希望在输入信号变化后12ns再更新输出结果,假设在15ns时a发生变化,在27ns时,结果将被更新,但是如果在15ns到24ns这一段时间,a,b,ci又发生了变化,在27ns时,结果将按照最新的a,b,ci进行计算并被更新。

如果将程序修改成如下格式,仿真的结果不变。

module adder_t7a (co, sum, a, b, ci);
output co;
output [3:0] sum;
input [3:0] a, b;
input ci;
reg co;
reg [3:0] sum;
reg [4:0] tmp;
always @(a or b or ci)
begin
#12 tmp = a + b + ci; // 在15ns a发生变化时,启动该always块,但是12ns后即第27ns时才执行                         tmp = a + b + ci tmp才被赋值,因此赋值的是最近的a,b,ci变化的值
{co, sum} = tmp;
end
endmodule

如果将程序做如下修改,

module adder_t7b (co, sum, a, b, ci);
output co;
output [3:0] sum;
input [3:0] a, b;
input ci;
reg co;
reg [3:0] sum;
reg [4:0] tmp;
always @(a or b or ci)
begin
tmp = a + b + ci;  // 在15ns a发生变化时,启动该always块,执行该语句,然后就开始执行下一句。
#12 {co, sum} = tmp; // 所以tmp的值是15ns的值,再过12ns即27ns时赋值给输出。因此,中间的变换被忽视
end
endmodule

仿真的结果如下图所示:从15ns到27ns之间的变化被忽视。

结论:阻塞式赋值语句是一句一句执行的,一句没有执行完,下一句绝不会执行。正因为如此,在此例中在延时12个ns的时间里,不作任何处理,tmp值保持不变(2’b10),而且对敏感变量的变化不作反应。不要将延时放在阻塞式赋值语句的左侧,这是一种不好的代码设计方式。

2:阻塞式右延时赋值语句
看下面的例子:

module adder_t6 (co, sum, a, b, ci);
output co;
output [3:0] sum;
input [3:0] a, b;
input ci;
reg co;
reg [3:0] sum;
always @(a or b or ci)
{co, sum} = #12 a + b + ci; // 先计算a + b + ci的值,过12ns后赋值为输出
endmodule

它的仿真结果同adder_t7b。即 同 tmp = a + b + ci;                                 #12 {co, sum} = tmp;
下面两个例子的仿真结果和相同adder_t6

module adder_t11a (co, sum, a, b, ci);
output co;
output [3:0] sum;
input [3:0] a, b;
input ci;
reg co;
reg [3:0] sum;
reg [4:0] tmp;
always @(a or b or ci)
begin
tmp = #12 a + b + ci;
{co, sum} = tmp;
end
endmodule
module adder_t11b (co, sum, a, b, ci);
output co;
output [3:0] sum;
input [3:0] a, b;
input ci;
reg co;
reg [3:0] sum;
reg [4:0] tmp;
always @(a or b or ci)
begin
tmp = a + b + ci;
{co, sum} = #12 tmp;
end
endmodule

结论:不要将延时放在阻塞式赋值语句的右侧,这是一种不好的代码设计方式。
3:非阻塞式左延时赋值语句
看例子:

module adder_t2 (co, sum, a, b, ci);
output co;
output [3:0] sum;
input [3:0] a, b;
input ci;
reg co;
reg [3:0] sum;
always @(a or b or ci)
#12 {co, sum} <= a + b + ci;
endmodule

它的仿真结果同adder_t1

结论:不要将延时放在非阻塞式赋值语句的左侧,这是一种不好的代码设计方式。
4:非阻塞式右延时赋值语句
看例子:

module adder_t3 (co, sum, a, b, ci);
output co;
output [3:0] sum;
input [3:0] a, b;
input ci;
reg co;
reg [3:0] sum;
always @(a or b or ci)
{co, sum} <= #12 a + b + ci;
endmodule

该例子的输出结果能随时跟踪输入信号的变化,仿真结果如下

结论:使用非阻塞式右延时赋值语句可以,输出结果能够跟随输入的变化,建议使用
5:非阻塞式右延时多重赋值语句
看例子

module adder_t9c (co, sum, a, b, ci);
output co;
output [3:0] sum;
input [3:0] a, b;
input ci;
reg co;
reg [3:0] sum;
reg [4:0] tmp;
always @(a or b or ci or tmp)
begin
tmp <= #12 a + b + ci;
{co, sum} <= tmp;
end
endmodule

该例子的输出结果和adder_t3相同,但是一定要注意将tmp也要列入敏感变量列表中去。或者使用如下程序,也能得到和adder_t3相同的结果。

module adder_t9d (co, sum, a, b, ci);
output co;
output [3:0] sum;
input [3:0] a, b;
input ci;
reg co;
reg [3:0] sum;
reg [4:0] tmp;
always @(a or b or ci or tmp)
begin
tmp <= a + b + ci;
{co, sum} <= #12 tmp;
end
endmodule

结论:使用非阻塞式右延时多重赋值语句,一定要将内部定义的变量也写到敏感变量表中
6:连续赋值语句
看例子

module adder_t4 (co, sum, a, b, ci);
output co;
output [3:0] sum;
input [3:0] a, b;
input ci;
assign #12 {co, sum} = a + b + ci;
endmodule
module adder_t5 (co, sum, a, b, ci);
output co;
output [3:0] sum;
input [3:0] a, b;
input ci;
assign {co, sum} = #12 a + b + ci;
endmodule

该例子的输出结果和adder_t3相同,
结论:使用连续性延时赋值语句,是一种良好的代码风格

Verilog语言设计增加延时的正确方法相关推荐

  1. 基于Modelsim的verilog语言设计AES加密解密(硬件电路HDL)

    全程手撕AES加密(verilog) 以下部分截图若涉及侵权,及时联系,随时撤销! 关于AES的原理我不多叙述,博客众多大佬比我厉害的多,该篇文章仅用来纪念自己的学习过程以及分享代码参考,毕竟有关这个 ...

  2. 使用Verilog语言描述计数器——脉动计数器;脉动计数器具有减法计数功能。采用模块设计和行为级设计方法。

    使用Verilog语言描述计数器--脉动计数器. 内容说明: 本次设计的计数器属于脉动计数器.使用Verilog语言设计,并且设计方法采用模块设计和简单的行为级设计.会有这两种设计的对比测试.最后,会 ...

  3. Verilog HDL语言设计实现过程赋值+译码器

    完成课本例题6.11.6.12,进行综合和仿真(功能仿真),查看综合和仿真结果,整理入实验报告. 6.11 module shiyan21(in,clk,out1,out2); input clk,i ...

  4. 数字电路之Verilog红绿灯设计

    数字电路之Verilog红绿灯设计 一.题目要求 二.分析题目 三.开始设计 四.结果分析 五.最后的话 写在前面:以下仿真实验设计应用的是Xilinx Vivado. 一.题目要求 题目要求应用Ve ...

  5. Verilog组合逻辑设计

    一.实验项目名称: Verilog组合逻辑设计 二.实验目的: 使用ISE软件和Verilog语言进行组合逻辑的设计与实现. 三.实验内容: 1.3-8译码器的设计和实现. 2.4位并行进位加法器的设 ...

  6. Verilog HDL设计方法

    Verilog HDL设计方法 一.采用Verilog HDL设计复杂数字电路的优点 1.1.传统设计方法--电路原理图输入法 1.2.Verilog HDL的标准化与软核的重用 1.3.软核.固核和 ...

  7. C语言设计一除法器,verilog 除法器

    verilog 除法器:利用二进制的除法翻译过来的硬件电路 1.1 实现算法 基于减法的除法器的算法: 对于32的无符号除法,被除数a除以除数b,他们的商和余数一定不会超过32位.首先将a转换成高32 ...

  8. 模型机设计(VERILOG)-模型机结构与Verilog语言

    前言 模型机是本学期电子电路课程的综合设计实验作业,主要利用数字电路逻辑部分的知识完成一个能实现多个指令的模型机,使用Verilog语言实现各个部件并完成最终的部件连接及验证.         在实现 ...

  9. 结束php语句的正确方法是,2011-2012-1-《PHP网页设计》试卷b

    中国成教大学 2011-2012学年第一学期 期末试卷(B卷) 课程名称<PHP网页设计>考生姓名_____________ 学号________ 考生须知:本课程为闭卷机试,考试时间为1 ...

最新文章

  1. ocp 工资_【中秋节加班费】2016中秋节加班工资怎么算,中秋节放假加班费的计算方法...
  2. 斯坦福:「目标检测」深度学习全面指南
  3. 有向加权图 最大弱连通分支_买入加权组合式等价对敲
  4. oracle 数据库回闪,各种数据库闪回的总结
  5. 若依前后端分离如何修改title标题呢?
  6. CNN入门讲解:不一样的Softmax
  7. 利用python实现冒泡排序_利用python实现冒泡排序
  8. 1e-5 java_内功心法 -- java.util.LinkedListE (5)
  9. 金南瓜 secs/gem协议 符合SEMI secs/gem协议 国际通讯协
  10. 物流车笔记——编码器原理
  11. 越是聪明人越要懂得下笨功夫!
  12. 广告联盟,拿什么拯救博客?
  13. 中国首个数字化糖尿病逆转项目在宁波正式启动
  14. Bazel 与 gtest:构建一个最简单的测试驱动开发环境
  15. 镭速传输安全设计第三篇:传输安全设计
  16. linux远程可视化
  17. centos7错误:can‘t create 事务 lock on /var/lib/rpm/.rpm.lock (权限不够)切换root用户
  18. poi导入excel数据思路
  19. 关于工作与生活——HP大中华区总裁孙振耀撰文谈退休并畅谈人生
  20. 厦门大学计算机专业导师排名,厦门大学计算机科学系研究生导师介绍:张德富...

热门文章

  1. 从0开始构建Arduino_STM32
  2. 参加第十六届智能车竞赛学生提出的问题-05-10
  3. 无线信标功能初步测试
  4. 乾勤科技-智能车竞赛培训计划
  5. 蚁群:微型机器人的社区
  6. rabbimq与PHP,PHP初次使用rabbitMQ
  7. 重写equals方法的hashcode_Java equals 和 hashCode 的这几个问题可以说明白吗?
  8. pdf压缩工具_PDF文件过大如何缩小,几步教你完成压缩
  9. oracle三种分区的方式,Oracle 分区表 总结大全(3)
  10. python互斥锁_Python多线程如何使用互斥锁