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丰富,更适合做时序控制
此外,在各家设计公司里,这样的代码是绝对不允许出现的,而是要有严格的代码规范。
希望我的回答对你能有帮助!追问
哥 我错了。。。。。
我正在的学习 为了小弟不走歪路。。。给点意见吧,,,我正在搞数据采集呢,,,,谢了
个人浅见:硬件描述语言,语言是次要的,主要的是算法。对语言可以上网上查一查写代码的一些相关标准,这些标准你知道了,你就会发现,其实算法相同那么大家写出的代码都差不多(这点和其他高级语言例如C、matlab等不同),这也是实际所需要的,因为标准是大家公认的在硬件实现时占用的面积最小,不会对硬件有浪费。且性能也很好,不会出错。
祝你顺利。
真正理解阻塞逻辑赋值与非阻塞逻辑赋值
真正理解阻塞逻辑赋值与非阻塞逻辑赋值
参考文献
[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 阻塞赋值与非阻塞赋值 Blocking assignment和NonBlocking assignment