verilog 关于阻塞与非阻塞赋值同时使用时的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了verilog 关于阻塞与非阻塞赋值同时使用时的问题相关的知识,希望对你有一定的参考价值。

举一例子
always @ (posedge CLK or begedge RST)
begin
if(~RST)begin a<=1'b0;b<=1'b0; end
else begin
a=b;
b<=b+1'b1;
end
end
请问在RST后的第一个CLK时钟上升沿后 a 和 b 的 输出是什么
b应该不会立马就赋值给a吧?
所以a还是0
b输出1?
是否是这样
我是否可以这么理解 就是说 非阻塞的赋值只在于上升沿来的那一瞬间,利用这个时刻系统的初值进行赋值,而它的输出是在一个延时“t”后,而阻塞赋值是不是就是说会有个值的相互传递过程?
不想自己仿真 呵呵 你们能帮我解答下吗?

其实时序逻辑中,信号有一定的保持时间。使用非阻塞赋值的时候,<=右边的信号变化,也不会马上对左边的信号造成影响,而是要等到一个周期之后。而组合逻辑中使用阻塞赋值,右边的信号变化,会立即对左边的信号造成影响。
阻塞赋值更像是顺序执行,而非阻塞赋值更符合并行执行。
比如always块中有:
y = a ;
y = y + b;
那么这两句和y = a + b;效果是一样的。就是说阻塞赋值中,a的值要赋值给y以后,才会执行下一条y+b, 而非阻塞赋值就不是这样,前一句和后一句同时执行,不会影响下一句。

PS:研究阻塞赋值和非阻塞赋值,有意义,可以多去搜搜文章。但这样研究代码,确实没意义。这段语句综合都过不了,一个always块中不允许同时出现阻塞赋值与非阻塞赋值追问

3Q
是不是多看优秀的代码会有帮助?
小弟正在搞CPLD+CY7C68013A+LABVIEW+AD+DA的数据采集控制系统。。。
给点意见吧把,。。。

追答

一般来说,看多了别人的模块,自己慢慢吸收就会做了,多看别人做的很重要,先模仿才有创造。
别的,多谷歌,多看看器件官网,会有很多应用笔记告诉你怎么做。比如你第一个USB控制器,很多器件都有相应的应用笔记。AD/DA也类似。
题外话,不知道你用的那款CPLD,一般来说FPGA的触发器资源比CPLD丰富,更适合做时序控制

参考技术A 恕我直言,你这样的研究没什么意义,这种非正规的代码写法可能会出现很多你意想不到的问题,即使仿真通过了,这也没有实际应用价值。always语句中一般不能有非阻塞赋值语句,除非他描述的是组合逻辑电路,VerilogHDL是硬件描述语言,代码的简洁是次要的,主要是代码对应的电路要简洁(用的元件最少,占的面积最小等)。
此外,在各家设计公司里,这样的代码是绝对不允许出现的,而是要有严格的代码规范。
希望我的回答对你能有帮助!追问

哥 我错了。。。。。
我正在的学习 为了小弟不走歪路。。。给点意见吧,,,我正在搞数据采集呢,,,,谢了

追答

个人浅见:硬件描述语言,语言是次要的,主要的是算法。对语言可以上网上查一查写代码的一些相关标准,这些标准你知道了,你就会发现,其实算法相同那么大家写出的代码都差不多(这点和其他高级语言例如C、matlab等不同),这也是实际所需要的,因为标准是大家公认的在硬件实现时占用的面积最小,不会对硬件有浪费。且性能也很好,不会出错。
祝你顺利。

本回答被提问者采纳
参考技术B dfdg

真正理解阻塞逻辑赋值与非阻塞逻辑赋值

真正理解阻塞逻辑赋值与非阻塞逻辑赋值

参考文献

[1]、数字芯片实验室(微信公众号)

项目简述

因为最近参加Xilinx暑假计划比较忙,已经很久没写文章了,这篇博客我们将重点讲述Verilog中阻塞逻辑赋值‘=’、非阻塞逻辑赋值‘<=’。看到这里不免大家要嘲笑,这谁不知道,文章的内容咋么越写越倒退了。其实不是这样,绝大多数的同学理解阻塞赋值与非阻塞赋值是组合逻辑语句用阻塞赋值 ‘=’、时序逻辑用非阻塞逻辑赋值‘<=’。那么真的是这样吗? 答案是否定的,其实组合逻辑语句一定用阻塞赋值 ‘=’,时序逻辑也可以用阻塞逻辑赋值‘=’。

本次实验所用到的软硬件平台如下:
1、VIVADO 2019.1
2、Modelsim 10.7

举例说明

其实阻塞逻辑赋值与非阻塞逻辑赋值最明显的区别就是:是否在整个代码块执行完毕再更新代码块中的数值。对于阻塞赋值 ‘=’被赋值的变量立刻发生变化,非阻塞逻辑赋值‘<=’会等到整个代码块运行结束后再进行变量的更新。接下来将以一道题目来解释于阻塞赋值 ‘=’出现在时序逻辑中的例子。

题目要求: 将一个串行执行的C语言算法转化为单拍完成的并行可综合verilog。
C语言源码如下:

unsigned charcal_table_high_first(unsignedcharvalue)

unsigned char i ;
unsigned char checksum = value ;
for (i=8;i>0;--i)

	if (check_sum& 0x80)
	
		check_sum = (check_sum<<1) ^ 0x31;
	 
	else
	
		check_sum = (check_sum << 1);
	

return check_sum;

针对上面的函数输入相应的变量检测我们接下来代码实现的正确性:

value =0x0:check_sum=0x0
value =0x1:check_sum=0x31
value =0x2:check_sum=0x62
value =0x3:check_sum=0x53
value =0x4:check_sum=0xc4
value =0x5:check_sum=0xf5
value =0x6:check_sum=0xa6
value =0x7:check_sum=0x97
value =0x8:check_sum=0xb9
value =0x9:check_sum=0x88
value =0xa:check_sum=0xdb
value =0xb:check_sum=0xea
value =0xc:check_sum=0x7d

这里可以看出题意上的要求是单拍完成,这个题很想CRC校验的问题,整个CRC校验每个字节的输入也必须再单拍内完成,还记得当时的博客我们咋么进行实验的吗,就是将每一位输出表达式进行彻底展开,然后在一拍之后输出,不太明白的同学,可以查看这篇博客基于FPGA的千兆以太网的实现(3),但是在进行输出展开的时候特别耗费时间,而且还有可能出错,那么有没有更好的办法进行计算呢?接下来我们将充分利用组合逻辑来实现这题目。

在进行写代码时,首先进行以下分析:
该算法逻辑如下:输入一个8bit的数,首先判断最高位是否为1,如果为1则左移一位,并且和8‘b00110001异或;如果最高位不为1则左移一位。此过程执行8次。

我们可以看出**:任何数与0异或都等于它本身**,即0^x=x。所以我们可以把算法流程变换为:8’h31 = 8’b00110001, 8’h00 = 8’b00000000,设左移前最高位为M,可以将判断左移前最高位是否为1的过程省略,直接与8’b00MM000M异或,此时流程图可以简化为:

那么接下来我们将给出上面硬件逻辑的代码,从代码中我们便可以看出时序逻辑电路中阻塞逻辑赋值的重要性。

正确代码

可综合代码

将上述的题目使用verilog实现,代码如下:

`timescale 1ns / 1ps
// *********************************************************************************
// Author       : zhangningning
// Email        : nnzhang1996@foxmail.com
// Website      : https://blog.csdn.net/zhangningning1996
// Module Name  : test.v
// Create Time  : 2020-08-05 20:49:16
// Revise       : 2020-08-05 20:49:16
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************


module test(
    input                   sclk            ,
    input                   rst_n           ,
    input           [ 7:0]  data            ,
    input                   data_en         ,
    output  reg     [ 7:0]  check_sum       ,
    output  reg             check_sum_en    
);
 
//========================================================================================\\
//**************Define Parameter and  Internal Signals**********************************
//========================================================================================/

 
//========================================================================================\\
//**************     Main      Code        **********************************
//========================================================================================/
integer                     i               ;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        check_sum               =          8'd0;
    else if(data_en == 1'b1)
        for(i = 0 ; i < 8 ; i = i+1)
            if(i == 0)
                check_sum           =          data[6:0],1'b0^(8data[7] & 8'h31);
            else
                check_sum           =          check_sum[6:0],1'b0^(8check_sum[7] & 8'h31);
    else
        check_sum               =          8'd0;

always @(posedge sclk)
    check_sum_en                <=         data_en;


endmodule

同学们可以看到,代码是多么简单,但是注意这里一定要是阻塞赋值,否则就不对,下面的代码会说明这个问题

大家可以注意这个代码风格很像VHDL,确实不太想我们平时写的代码,因为这样我们不能做到很好的时序把控。

测试代码

tb模块:

`timescale 1ns / 1ps
// *********************************************************************************
// Author       : zhangningning
// Email        : nnzhang1996@foxmail.com
// Website      : https://blog.csdn.net/zhangningning1996
// Module Name  : tb.v
// Create Time  : 2020-08-05 21:07:15
// Revise       : 2020-08-05 21:07:15
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************


module tb();

reg                     sclk            ;
reg                     rst_n           ;
reg             [ 7:0]  data            ;
reg                     data_en         ;
wire            [ 7:0]  check_sum       ;
wire                    check_sum_en    ;

initial begin
    sclk            <=          1'b0;
    rst_n           =           1'b0;
    data            =           8'd0;
    data_en         =           1'b0;
    #(100);
    rst_n           =           1'b1;
    #(100);
    data_en         =           1'b1;
    #(200);
    data_en         =           1'b0;
    #(100);
    $stop;
end
always  #10     sclk        <=      ~sclk;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        data        <=          8'd0;
    else if(data_en == 1'b1)
        data        <=          data + 1'b1;
    else
        data        <=          data;


          




test test_inst(
    .sclk                   (sclk                   ),
    .rst_n                  (rst_n                  ),
    .data                   (data                   ),
    .data_en                (data_en                ),
    .check_sum              (check_sum              ),
    .check_sum_en           (check_sum_en           )
);

endmodule

仿真结果

仿真结果如下:

将上面的结果与C语言的运行结果相对比,可以验证我们实验的正确性

错误代码

前面我们使用的是阻塞赋值,如果我们将其换成非阻塞赋值,那么实验结果将会发生改变,详情如下。

可综合代码

test模块:

`timescale 1ns / 1ps
// *********************************************************************************
// Author       : zhangningning
// Email        : nnzhang1996@foxmail.com
// Website      : https://blog.csdn.net/zhangningning1996
// Module Name  : test.v
// Create Time  : 2020-08-05 20:49:16
// Revise       : 2020-08-05 20:49:16
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************


module test(
    input                   sclk            ,
    input                   rst_n           ,
    input           [ 7:0]  data            ,
    input                   data_en         ,
    output  reg     [ 7:0]  check_sum       ,
    output  reg             check_sum_en    
);
 
//========================================================================================\\
//**************Define Parameter and  Internal Signals**********************************
//========================================================================================/

 
//========================================================================================\\
//**************     Main      Code        **********************************
//========================================================================================/
integer                     i               ;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        check_sum               <=         8'd0;
    else if(data_en == 1'b1)
        for(i = 0 ; i < 8 ; i = i+1)
            if(i == 0)
                check_sum           <=         data[6:0],1'b0^(8data[7] & 8'h31);
            else
                check_sum           <=         check_sum[6:0],1'b0^(8check_sum[7] & 8'h31);
    else
        check_sum               <=         8'd0;

always @(posedge sclk)
    check_sum_en                <=         data_en;


endmodule

测试模块的代码与上面的相同,这里不在给出。

仿真结果

我们将上面的代码进行仿真,结果如下:

从上面可以发现仿真结果与C语言的仿真不一致,所以通过这篇博客可以学会阻塞赋值与非阻塞赋值的重要性。

总结

通过上面的描述,同学们应该知道时序逻辑中也是可以用阻塞赋值的,这在VHDL中是比较常用的,同时也会带来一些列的时序问题,所以不建议多用。

创作不易,认为文章有帮助的同学们可以关注、点赞、转发支持。(txt文件、图片文件在群中)对文章有什么看法或者需要更近一步交流的同学,可以加入下面的群:

以上是关于verilog 关于阻塞与非阻塞赋值同时使用时的问题的主要内容,如果未能解决你的问题,请参考以下文章

verilog中为啥非阻塞赋值要用绝对时延

阻塞赋值和非阻塞赋值有何区别

Verilog 阻塞赋值与非阻塞赋值 Blocking assignment和NonBlocking assignment

Verilog -- 阻塞与非阻塞的仿真与综合

在 verilog中的非阻塞赋值在啥时候赋值时刻结束?

verilog 阻塞和非阻塞啥区别啊?