verilog_阻塞赋值与非阻塞赋值

verilog_阻塞赋值与非阻塞赋值

阻塞赋值的赋值号用“=”表示。为什么称这种赋值方式为阻塞赋值呢?因为对应的电路结构往往与触发沿没有关系,只与输入电平的变化有关系。阻塞赋值的操作可以认为是只有一个步骤的操作,即计算赋值号右边的语句并更新赋值号左边的语句,此时不允许有来自任何其他Verilog语句的干扰,直到现行的赋值完成时刻,即把当前赋值号右边的值赋值给左边的时刻完成后,它才允许下一条的赋值语句的执行。串行块(begin-end)中的各条阻塞型过程赋值语句将以它们在顺序块后的排列次序依次执行。阻塞型过程赋值语句的执行过程是:首先计算赋值号右边的值,然后立即将计算结果赋值给左边,赋值语句结束,变量值立即发生改变。阻塞的概念是指在同一个always块中,其后面的赋值语句从概念上是在前一句赋值语句结束后再开始下面的赋值。

a=1,b=2,c=3
begin
	a=b+2;
	b=c+2;
	c=a+2;
end

执行完后a=4,b=5,c=6。其为顺序执行。
总结:每条语句执行之后才能执行下一条语句!与其他语言的赋值功能几乎相同!
非阻塞赋值
的赋值号用“<=”表示。为什么称这种赋值方式为非阻塞赋值呢?这是因为对应的电路结构往往与触发沿有关系,只有在触发沿的时刻才能进行非阻塞赋值。非阻塞操作开始时计算非阻塞赋值符的赋值号右边的语句,赋值操作结束时刻才更新赋值号左边的语句,**可以认为是两个步骤(赋值开始时刻和结束时刻)来完成非阻塞赋值。在计算非阻塞语句赋值号右边的语句和更新赋值号左边的语句期间,**其他的Verilog语句包括其他的Verilog非阻塞赋值语句都能同时计算赋值号右边的语句和更新赋值号左边的语句,允许其他的Verilog语句同时进行操作。非阻塞赋值的操作可以看作为两个步骤的过程:在赋值开始时刻,计算赋值号右边的语句。在赋值结束时刻,更新赋值号左边的语句。注意:非阻塞操作只能用于对寄存器类型变量进行赋值,因此只能用于“initial”和“always”块中,不允许用于连续赋值“assign”。

a=1,b=2,c=3
begin
	a<=b+1;
	b<=c+1;
	c<=a+1;
end

执行完之后:a=3,b=4,c=2.

下面我们以代码仿真来具体分析

//阻塞赋值
module(
    input wire  sys_clk,//时序逻辑
    input wire  sys_rst_n,
    input [1:0] in,
    output [1:0] out
);

reg [1:0] in_reg,
always@(posedge sys_clk or negedge sys_rst_n)//异步复位
    if(!sys_rst_n)begin
        in_reg = 2'b00;
        out    = 2'b00'
    end
    else
        in_reg = in;
        out = in_reg

endmodule

看一下综合之后的RTL视图,可以看出其综合为D触发器在这里插入图片描述

根据以前学的内容,我们知道一个寄存器就是“延一拍”,所以该仿真波形和前面的RTL视图刚好对应,发现输入信号in和中间变量in_reg、输出信号out的关系就是延迟一拍的关系,但是为什么只是延迟一拍呢?首先中间变量in_reg一定要等待复位被释放后且第一个时钟上升沿来到时才会被赋值为输入信号in的值,所以会比输入信号in延迟一拍,而中间变量in_reg和输出信号out却没有延迟一拍的关系了,而是在同一时刻同时变化的,因为我们使用的是阻塞赋值,也就是说只要赋值号右边的表达式的值有变化,赋值号左边的表达式的值也将立刻变化,所以我们最终看到的结果是中间变量in_reg和输出信号out是同时变化的。

下面的例子可以说明这个问题: `
在这里插入图片描述

根据上面RTL代码综合出的RTL视图如图 16-3所示,我们可以看到综合出的结果有两组寄存器,这是和使用阻塞赋值所综合的RTL视图所不同的。
在这里插入图片描述

为了进一步验证,我们通过Testbench进行仿真验证一下结果,并和阻塞赋值(=)的波形进行对比。在这里插入图片描述
我们让仿真运行了500ns即可得到较好的观察效果。同样该仿真波形和其对应的RTL视图也是刚好对应的,我们发现输入信号in和中间变量in_reg是延迟一拍的关系,而中间变量in_reg和输出信号out也是延迟一拍的关系,也就是输入信号in和输出信号out一共是延迟两拍的关系,为什么会这样呢?首先中间变量in_reg一定要等待复位被释放后且第一个时钟上升沿来到时才会被赋值为输入信号in的值,所以会比输入信号in延迟一拍,这是和阻塞赋值过程相同的,但是接下来就不一样了,因为我们使用的是非阻塞赋值,也就是说只要赋值号右边的表达式的值有变化,赋值号左边的表达式的值也不会立刻变化,需要等待下一次时钟沿到来时一起变化,所以我们最终看到的结果是输出信号out相对于输入信号是打了两拍的关系。

总结
本章主要讲解了阻塞赋值(=)与非阻塞赋值(<=)会给设计的电路所产生的差异,重新理解阻塞赋值与非阻塞赋值的原理和意义,能够使我们在以后的设计中正确设计出符合我们所想要表达的电路。
阻塞赋值(=):该语句结束时就完成赋值操作,前面的语句没有完成前,后面的语句是不能执行的。在一个过程块内多个阻塞赋值语句是顺序执行的。
非阻塞赋值(<=):一条非阻塞赋值语句的执行是不会阻塞下一条语句的执行,也就是说在本条非阻塞赋值语句执行完毕前,下一条语句也可开始执行。非阻塞赋值语句在过程块结束时才完成赋值操作。在一个过程块内的多个非阻塞赋值语句是并行执行的。
最后我们总结在编写RTL代码时推荐的一些规范,详细如下:
(1)在编写时序逻辑的代码时采用非阻塞赋值的方式
计算RHS时,所有的变量值均是触发沿到来前的值,更新的值LHS作为触发沿后的值,并且保持到下一个触发沿到来时候,等待更新。这样,就可以使得在同一个块中非阻塞赋值语句不必要求出现的顺序,都是在全部进行RHS计算后同时更新LHS的值。非阻塞赋值可以简单的认为是赋予下一状态的值。
(2)使用always块来编写组合逻辑的代码时要用阻塞赋值的方式
使用always块建立组合逻辑电路模型时不要忘记always块中的敏感列表一定要使用电平触发的方式,然后在always块中使用阻塞赋值语句就可以实现组合逻辑,这样做既简单且方针又快又好,这样的风格是值得推荐的。
(3)在同一个always块中不要既要用非阻塞赋值又用阻塞方式赋值
在同一个always块中对同一个变量既进行阻塞赋值又进行非阻塞赋值会产生综合不可预测的结果,不是可综合的Verilog风格。
(4)虽然锁存器电路建模是我们不推荐的,但是如果使用到要采用非阻塞赋值的方式。
使用非阻塞赋值实现时序逻辑,实现锁存器是最为安全的。
(5)一个always块只一个变量进行赋值
因为always块是并行的,执行的顺序是随机的,综合时会报多驱动的错误,所以严禁在多个always块中对同一个变量赋值;当然也不推荐一个always对多个变量进行赋值,虽然这种方式是允许的,但如果过多会导致代码的混乱且不易后期的维护和修改(本例之所以写在一起时因为变量不多,其次是为了进行对比得出本章的实验效果),不是本教程推荐的设计方法。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

<往事随风>

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值