Verilog赋值和结构说明语句,赋值语句

“本文主要分享了在Verilog设计过程中一些经验与知识点,主要包块语句、阻塞赋值和非阻塞赋值以及结构说明语句(initial, always, task, function)。”

01

块语句

顺序块 begin…end

块内的语句是按照顺序执行的;

块内的每条语句延时控制都是相对于上条语句结束的时刻;

仿真时,执行到最后一条语句该语句块执行结束。

并行块fork…end

块内的语句是按照独立的同时开始执行的;

块内的每条语句延时控制都是相对于程序进入该语句块的时刻而言;

仿真时,所需最长时间的语句执行结束后,该语句块执行结束。

例:

reg [7:0] l1,l2; reg[7:0]k1,k2;initialbeginl1=0;l2=0;#15l1=2;#10l2=8;endinitialforkk1=0;k2=0;#15k1=2;#10k2=8;join仿真结果如下:

从仿真结果可以看出:在顺序块中,15ns的时候,l1被赋值为8’h2,在25ns的时候,l2被赋值为8’h8;而在并行块中,10ns的时候,k2被赋值为8’h8,在15ns的时候,k1被赋值为8’h2。可以很容易明白顺序块和并行块的特性。

02

阻塞赋值和非阻塞赋值

  • 阻塞赋值(Blocking)

阻塞赋值用“=”表示:在赋值时,先计算等号(“=”)右边部分的值,这时赋值语句不允许其他的语句干扰,直到赋值完成,也就是说“阻塞”是指在当前的赋值完成前阻塞其他类型的赋值任务。
  • 非阻塞赋值(Non_Blocking)

非阻塞赋值用“<=”表示:在赋值操作时刻开始计算非阻塞赋值右边部分的值,赋值操作结束时刻才更新左边部分。

例1:组合逻辑中的阻塞与非阻塞

阻塞代码如下:
always@(a,b,c,d) begin i1 = a & b; i2 = c & d; i3 = i1 & i2;end仿真结果如下:

非阻塞代码如下:
always@(a,b,c,d) begin i1 <=>

仿真结果如下:

可以看出i1和i2在阻塞和非阻塞中结果相同,但是i3的结果却不同。这是因为在阻塞赋值中,i3的赋值使用的是i1和i2更新后的值,而非阻塞赋值中i3的赋值则使用的是i1和i2更新前的值。要想解决这一问题,则需要将“always@(a,b,c,d)”改成“always@(a,b,c,d,i1,i2)”代码如下:
always@(a,b,c,d,i1,i2) begin i1<=a&b;>

综上,组合逻辑中更适合用阻塞赋值语句。

例2:时序逻辑中的阻塞和非阻塞。

以反馈振荡器的代码为例。非阻塞赋值代码:
always@(posedge clk,posedge rst) begin if(rst) a1 <=0;>

阻塞赋值代码:

always@(posedge clk,posedge rst) begin if(rst) b1 = 0; else b1 = b2; endalways@(posedgeclk,posedgerst) begin if(rst) b2 = 1; else b2 = b1; end

仿真结果如下:

可以看出阻塞赋值语句并不能达到我们想要的效果;而且综合后阻塞赋值语句中,无法确定哪个always块中的时钟沿先到达,哪个always块中的时钟后到达,所以存在一个冒险竞争的问题。综上,时序逻辑中更适合用非阻塞赋值语句。

03

结构说明语句(initial, always, task, function)

  • 语句initial

语法格式如下:
initial begin // Add code hereend一般initial语句用于测试文件的编写;但是随着编译器的进步,现在也可以综合,常用于一些变量的初始化。无论是用在什么场景,initial语句只执行一次。
  • 语句always

语法格式如下:always

例1:生成仿真时的信号波形

always可以用于仿真时的波形生成:always #5 clk = ~clk;这个例子就形成了一个周期为10ns(时间单位ns根据`timescale确定)的方波,常用来描述时钟信号(如果将#5去掉,那么会生成一个延迟为0的无限循环跳变过程,会发生仿真锁死,这是不推荐的)。仿真结果如下:

例2:

实现锁存器和触发器

always@(posedge clk or posedge rst) begin if(rst) cnt <=>

例3:实现组合逻辑

利用always实现组合逻辑时,要将所有的信号放进敏感列表,而时序逻辑中则不需要。
always@(aorborc) beginx=x+1;end上面的代码表示,a、b、c中任意电平发生变化,begin…end语句就会被触发。仿真结果如下所示:

always@(a or b or c or d or e) begin out = a + b + c + d + e;end如上所示,因为敏感列表比较长,容易写错,所以Verilog又提供了两个特殊的符号:@*和@(*)。简化代码如下:
always@(*)beginout=a+b+c+d+ e;end仿真结果如下图所示:

注意:always模块内被赋值的每一个信号都必须定义为reg型。
  • 语句task

语句task的定义:

task ;

<端口及数据类型声明语句>;

;

endtask

示例代码如下:
reg [7:0] j,k,i,x; always@(posedge clk or posedge rst) begin if(rst) begin i <=>

  • 语句function

函数(function)的目的是返回一个用于表达式的值。

语句function的定义:

function(函数名)

begin

end

endfunction

示意代码如下:
reg [7:0] i,j; reg [8:0] sum_data; always@(posedge clk or posedge rst) begin if(rst) begin i <=>

仿真结果如下图所示:

注意:initial、always、task和function都是可以综合的。

审核编辑:郭婷

相关推荐

相关文章