4、赋值
Verilog HDL有两种为变量赋值的方法
一种叫做连续赋值(Continuous Assignment),另一种叫做过程赋值(Procedural Assignment)。
过程赋值又分为阻塞赋值(Blocking Assignment)和非阻塞赋值(Nonblocking Assignment)。
4.1 连续赋值
连续赋值是为线网型变量提供驱动的一种方法,它只能为线网型变量赋值,并且线网型变量也必须用连续赋值的方法赋值。
最基本的格式:assign # [延时量] 线网型变量名 =赋值表达式
赋值表达式可以是 a.标量 b.向量线网 c.向量寄存器 d.函数调用;
执行过程:连续赋值语句总是处于激活状态,只要右侧表达式中的任意一个操作数发生变化,表达式就会被立即重新计算,并且将结果赋值给对象。
wire a,b;
assign a = b;
wire [7:0] a,b;
assign a = b;
wire [7:0] a,b;
assign a[3] =b[1];
wire [7:0] a,b;
assign a[3:0] =b[3:0];
wire a,b;
wire [1:0]c;
assign c = {a,b};
4.2 过程赋值
过程赋值提供了为寄存器型变量赋值的方法,出现的位置是在各种块结构中,例如always块、 initial块等。
经过赋值后,变量(reg,integer,real,time)的取值保持不变,直到另一条赋值语句对变量重新赋值为止。
过程赋值又分为阻塞赋值和非阻塞赋值两种。
1、阻塞赋值
阻塞赋值方式,使用“=”为变量赋值。
“阻塞”是指在当前的赋值完成前阻塞其他类型的赋值任务。但如果右端表达式含有延时语句,则在延时没结束前不会阻塞其他赋值任务。
赋行值按顺序执行,只有上一条语句执行完成(赋值结束),才会执行(赋值)下一条语句;在赋值结束以前不可以进行其它操作,在赋值结束后才继续后面的操作。这个过程好像阻断了程序的运行,因而被称为阻塞赋值。
显然,连续的阻塞赋值操作是顺序完成的。
如a=b,在每个右端表达式计算完后立即赋给左端变量,也就是在该语句结束时就完成了赋值操作。
2、非阻塞赋值
非阻塞赋值使用“<=”为变量赋值,在执行到连续的非赋值语句时,仅仅对“<=” 右端表达式进行评估,但并不立即赋值给左端,然后继续执行后面的操作,当块结构结束后所有的非阻塞赋值同时进行赋值。这个过程好像没有阻断程序的运行,因而被称为非阻塞赋值。
执行步骤:
(1)读取操作数,计算右侧表达式的值并保存在临时变量中;
(2)对左侧的赋值由仿真器调度到相应的仿真时刻;
(3)每个赋值操作在被调度的仿真时刻完成。
典型应用:流水线建模 互斥数据传输
问题:仿真速度下降 内存使用量增加
对组合逻辑建模采用阻塞式赋值;
最时序逻辑建模采用非阻塞式赋值;
用多个always块分别对组合和时序逻辑建模。
5、过程模块
begin..end 块内语句是串行执行的,fork..join 是并行执行的;
case语句的分支是并行执行,if语句的选择分支是串行执行。
(1)initial模块
在仿真时,initial模块只执行一次,如果有两个initial模块,同时开始从0时刻执行。
initial
forever begin // forever语句必须写在initial模块中,用于产生周期性波形。
#5 clk = ~clk; //延时控制
a = 0;
...
end
...
end
(2)always模块
一直重复执行的。括号内是多个触发条件,只要有一个成立,就启动块内启动执行。
always @(a or b or posedge clk or negedge y) begin
...
end
(3)task模块
(4)function模块
6、语句块
(1)begin..end 块内语句是串行执行的
(2)fork..join 是并行执行的
并行:各自独立地同时开始执行。