微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > FPGA,CPLD和ASIC > 关于非阻塞赋值和begin end块的问题

关于非阻塞赋值和begin end块的问题

时间:10-02 整理:3721RD 点击:
一直被这个问题困惑,还请各位指导,多谢。
begin end是个顺序块,语句是一条一条执行的,而非阻塞赋值是先计算RHS的值,再将RHS的值赋给LHS,那么在begin end当中的非阻塞赋值的执行顺序是怎样的呢?也就是说它计算RHS是同时的吗?赋值给LHS是同时的吗?还是都按顺序执行呢?

比如说下面这个例子:
always @(posedge clk)
begin
  if(!rst)
   cnt<=0;
  else
   begin
     cnt<=cnt+1;
     if(cnt==2)
       cnt<=0;
     else;
   end
end
当cnt==2的时候,cnt+1也执行啊,为什么最后的结果会使cnt==0?
不知道问题有没有表达清楚,烦请各位指教,感激不尽!

呵呵,我也一直有这样的困惑

cnt <= cnt + 1;
if(cnt==2)
    cnt <= 0;
else;
这段代码等于
if(cnt==2)
   cnt <= 0;
else
   cnt <= cnt + 1;

类似的编码风格也适用于case语句:
rst = 0;
case(sel)
1: rst = 1;
2: rst = 2;
endcase
等于
case(sel)
1: rst = 1;
2: rst = 2;
default: rst = 0;
endcase


感谢回答,不过你说的这个我知道。我的困惑在于begin end是个顺序块,而非阻塞赋值是非顺序的,这个计算RHS和赋值LHS的过程是顺序的还是并行的?

要从软件思维转变到硬件思维。用时钟上升沿同步的电路,if(cnt==2)判断的是上个周期的cnt值,而不是加1后的cnt值。

cnt+1执行了,但是cnt<=cnt+1没有执行赋值!


为什么呢?

0 ---------|
cnt + 1 --|

语句是并行的,但注意两点,语句执行后,其结果要在下一个触发时钟才有效,第二,你这个写法会导致重复赋值,这时候最后一个赋值才是最终输出。正确的写法:
if(cnt == 2)
    cnt <= 0;
else
    cnt <= cnt+1;

_       __
  0 ---------->| \     |  |
                    | |----|  |----> cnt
|->  cnt+1-->| /     |>|       |
|                            |_|       |
|--------<------------------<-|
如上图所示,(cnt + 1)是一个纯组合电路,它永远都在执行;中间是一个MUX选择器,他从0 和 (cnt+1) 中二选一,选择信号是(cnt==2). 最后一级是寄存器,他锁存选择器的结果。
小编要从硬件电路的角度去理解verilog, 其实阻塞,非阻塞等只是一些名词,帮助你理解代码的。只要你理解了实际电路的实现,这些词不必太在意.

9楼10楼正解!

简单的说if(cnt==2)这个条件会综合出一个和rst同等地位的信号,这个信号和rst经过或逻辑连接到DFF的reset端。
需要着重理解的是:语句的执行顺序是对仿真计算的过程而言的,从综合的角度来说,两条语句对应着DFF数据反馈逻辑和reset逻辑,显然reset逻辑的优先级在硬件结构上是更高的。
当cnt==2时仿真过程大致如下:
        1. 执行至cnt<=cnt+1语句时,cnt==2,cnt的未来值 cnt'==3;
        2. 执行至if语句时,条件表达式成立,reset信号变为有效,cnt的未来值cnt''==0;
        3. 根据物理结构的优先级最终选定cnt的未来值为cnt''==0;
        4. 当触发信号到来时,cnt的值更新为0;
另外,如果if语句中写为:cnt<=1的形式,那么if语句的条件表达式将综合为load使能信号;
注:上述综合结构是综合工具的parser直接翻译的中间结构,并非最终输出的网表结构,最终结果在对中间结构优化后可能会有变化

给你换一种coding style,看看能不能帮助你理解:
//===============================================
reg [msb:lsb]cnt_p;
reg [msb:lsb]cnt_r;
reg [msb:lsb]cnt;
assign cnt = cnt_r;
always @ (*) begin
    if (cnt_r == 'h2) begin
        cnt_p = 'b0;
    end
    else begin
        cnt_p = cnt_r + 1'b1;
    end
end
always @ (posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        cnt_r <= 'b0;
    end
    else begin
        cnt_r <= cnt_p;
    end
end
//===============================================



    正解。计算和赋值是两个步骤,这就是非阻塞和阻塞的最本质区别。理解了这一点,很多困惑都会迎刃而解



    确切的说是cnt+1的值被暂存在temp里面,其实3=2+1是被计算了的,只是因为没有到always的结尾尚未进行赋值。
非阻塞赋值并不是并行语句,也是有顺序执行的。其执行过程为:
执行到赋值语句时,计算赋值符号右边表达式的值,并暂存;
以同样的方式处理下一条赋值语句直到所有的赋值语句处理完;
该过程语句结束时,将暂存的值依次(按照语句顺序)赋值给赋值符号右边的信号。
因此在同一个时钟沿对同一个变量进行非阻塞赋值,后面的复制操作会覆盖掉前面的赋值操作。



    重复赋值,后面的覆盖前面的。

一个非阻塞的写法 引起这么多讨论, 学习了。
其实这样的写法本身就没考虑可综合性。
cnt <= cnt + 1;
if (cnt == 2)
   cnt <= 0;
换成这样就可综合且更易理解: cnt = (cnt == 2) ? 0 (cnt + 1);

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top