时间:2024.11.19
一、学习内容
1.阻塞赋值
阻塞赋值的赋值号用“=”表示。
对应的电路结构往往与触发沿没有关系,只与输入电平的变化有关系。阻塞赋值的操作可以认为是只有一个步骤的操作,即计算赋值号右边的语句并更新赋值号左边的语句,此时不允许有来自任何其他 Verilog 语句的干扰,直到现行的赋值完成时刻,即把当前赋值号右边的值赋值给左边的时刻完成后,它才允许下一条的赋值语句的执行。
串行块(begin-end)中的各条阻塞型过程赋值语句将以它们在顺序块后的排列次序依次执行。(顺序执行)
阻塞型过程赋值语句的执行过程是:首先计算赋值号右边的值,然后立即将计算结果赋值给左边,赋值语句结束,变量值立即发生改变。
阻塞的概念是指在同一个 always 块中,其后面的赋值语句从概念上是在前一句赋值语句结束后再开始下面的赋值。
2.非阻塞赋值
非阻塞赋值的赋值号用“<=”表示。
对应的电路结构往往与触发沿有关系,只有在触发沿的时刻才能进行非阻塞赋值。非阻塞操作开始时计算非阻塞赋值符的赋值号右边的语句,赋值操作结束时刻才更新赋值号左边的语句,可以认为是两个步骤(赋值开始时刻和结束时刻)来完成非阻塞赋值。在计算非阻塞语句赋值号右边的语句和更新赋值号左边的语句期间,其他的 Verilog 语句包括其他的 Verilog 非阻塞赋值语句都能同时计算赋值号右边的语句和更新赋值号左边的语句,允许其他的 Verilog 语句同时进行操作。
非阻塞赋值的操作可以看作为两个步骤的过程:在赋值开始时刻,计算赋值号右边的语句。在赋值结束时刻,更新赋值号左边的语句。(并列执行)
注意:
非阻塞操作只能用于对寄存器类型变量进行赋值,因此只能用于“initial”和“always”块中,不允许用于连续赋值“assign”。
3.总结
阻塞赋值(=):该语句结束时就完成赋值操作,前面的语句没有完成前,后面的语句是不能执行的。在一个过程块内多个阻塞赋值语句是顺序执行的。
非阻塞赋值(<=):一条非阻塞赋值语句的执行是不会阻塞下一条语句的执行,也就是说在本条非阻塞赋值语句执行完毕前,下一条语句也可开始执行。非阻塞赋值语句在过程块结束时才完成赋值操作。在一个过程块内的多个非阻塞赋值语句是并行执行的。
二、实验
1.准备工作
建立文件夹存放工程
2.绘制波形图和模块框图
模块框图
波形图
3.编写代码-阻塞赋值
module blocking
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire [1:0] in ,
output reg [1:0] out
);
//定义中间变量,方便仿真波形的观察
reg [1:0] in_reg;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
in_reg = 2'b0;
out =2'b0;
end
else //当复位信号无效时,对两个变量进行赋值
begin
in_reg =in;
out =in_reg;
end
endmodule
4.仿真验证-阻塞赋值
`timescale 1ns/1ns
module tb_blocking();
reg sys_clk;
reg sys_rst_n;
reg [1:0] in;
wire [1:0] out;
//用initial语句初始化时钟、全局复位信号和输入信号
initial
begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
in <= 2'b0;
#20
sys_rst_n <= 1'b1;
end
//生成模拟时钟
always #10 sys_clk =~sys_clk;
always #20 in <={$random}%2; //输入信号是两位宽,所以对4取余
//模块实例化
blocking blocking_inst
(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.in (in),
.out (out)
);
endmodule
5.打印结果-阻塞赋值
6.波形图-阻塞赋值
7.编写代码-非阻塞赋值
module blocking
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire [1:0] in ,
output reg [1:0] out
);
//定义中间变量,方便仿真波形的观察
reg [1:0] in_reg;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
in_reg = 2'b0;
out =2'b0;
end
else //当复位信号无效时,对两个变量进行赋值
begin
in_reg <=in;
out <=in_reg;
end
endmodule
8.仿真验证-非阻塞赋值
`timescale 1ns/1ns
module tb_blocking();
reg sys_clk;
reg sys_rst_n;
reg [1:0] in;
wire [1:0] out;
//用initial语句初始化时钟、全局复位信号和输入信号
initial
begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
in <= 2'b0;
#20
sys_rst_n <= 1'b1;
end
//生成模拟时钟
always #10 sys_clk =~sys_clk;
always #20 in <={$random}%2; //输入信号是两位宽,所以对4取余
//模块实例化
blocking blocking_inst
(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.in (in),
.out (out)
);
endmodule
9.打印结果-非阻塞赋值
10.波形图-非阻塞赋值
四、知识点和小技巧
编写 RTL 代码时推荐的一些规范总结
(1)在编写时序逻辑的代码时采用非阻塞赋值的方式
计算赋值号右边的信号时,所有的变量值均是触发沿到来前的值,更新的赋值号左边的信号作为触发沿后的值,并且保持到下一个触发沿到来时候,等待更新。这样,就可以使得在同一个块中非阻塞赋值语句不必要求出现的顺序,都是在全部进行赋值号右边的信号计算后同时更新赋值号左边的信号的值。非阻塞赋值可以简单的认为是赋予下一状态的值。
(2)使用 always 块来编写组合逻辑的代码时要用阻塞赋值的方式
使用 always 块建立组合逻辑电路模型时不要忘记 always 块中的敏感列表一定要使用电平触发的方式,然后在 always 块中使用阻塞赋值语句就可以实现组合逻辑,这样做既简单且方针又快又好,这样的风格是值得推荐的。
(3)在同一个 always 块中不要既要用非阻塞赋值又用阻塞方式赋值
在同一个 always 块中对同一个变量既进行阻塞赋值又进行非阻塞赋值会产生综合不可预测的结果,不是可综合的 Verilog 风格。
(4)虽然锁存器电路建模是我们不推荐的,但是如果使用到要采用非阻塞赋值的方
式。
使用非阻塞赋值实现时序逻辑,实现锁存器是最为安全的。
(5)一个 always 块只一个变量进行赋值
因为 always 块是并行的,执行的顺序是随机的,综合时会报多驱动的错误,所以严禁在多个 always 块中对同一个变量赋值;当然也不推荐一个 always 对多个变量进行赋值,虽然这种方式是允许的,但如果过多会导致代码的混乱且不易后期的维护和修改(本例之所以写在一起时因为变量不多,其次是为了进行对比得出本章的实验效果),不是推荐的设计方法。
标签:语句,12,always,阻塞,sys,reg,赋值 From: https://blog.csdn.net/2201_75297369/article/details/143807988