Verilog赋值和结构说明语句,赋值语句 2024-04-26 10:58:39 0 0 “本文主要分享了在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都是可以综合的。 审核编辑:郭婷 收藏(0)