SV 过程块
过程块
scope
在SV中,哪些语句应该放在硬件世界,哪些语句应该属于软件世界。将软件变量定义与硬件例化所在的空间称之为域。
硬件域:例化硬件的空间
- module ... endmodule
- interface ... endinterface
软件域:定义软件变量的空间
- program ... endprogram
- class ... endclass
语句块
用来将多个语句组织在一起,使得他们在语法上如同一个语句。
顺序块:语句置于关键字begin和end之间,块中的语句以顺序方式执行。
并行块:关键字fork和join/join_any/join_none之间的是并行块语句,块中的语句并行执行。
命名块
给每个块定义的标识名称,将块名加在begin或fork后面;
可以定义块内局部变量
允许定义的块被其他语句调用,如disable语句;
always
用来描述硬件时序电路和组合电路的正确打开方式,因此只能在 module 或者 interface 中使用;
用法: always @(敏感信号列表)
initial
只执行一次;
initial 和 always一样,无法被延迟执行,在仿真一开始都会同时执行;
initial 和 always之间在执行顺序上没有顺序可言;
initial 不可综合,用于测试;
initial 过程块可以在module、interface和program中使用;
使用 begin ... end 包裹;
function
可以在参数列表中指定输入参数(input)、输出参数(output)、输入输出参数(inout)、或者引用参数(ref);
可以返回数值或者不返回数值(void);如果返回,使用关键字return;
默认的数据类型是logic,例如 input [7:0] addr;
数组可以作为形式参数传递;
只有数据变量可以在形式参数列表中被 ref 修饰,线网类型不能;
在使用ref时,有时候为了保护数据对象只被读取而不被写入。可以使用const的方式来限定ref声明的参数;
支持默认值;
function int double_f0(int a); return 2*a; endfunction function void double_f1(input int a, output int b); b = 2*a; endfunction function void double_f2(inout int a); a = 2*a; endfunction function automatic void double_f3(ref int a); a = 2*a; endfunction initial begin: int v1, v2; v1 = 10; v2 = double_f0(v1); $display("v1 = %0d, double function result is %0d", v1, v2); v1 = 10; double_f1(v1, v2); $display("v1 = %0d, double function result is %0d", v1, v2); v1 = 10; $display("v1 is %0d before calling double_f2(v1)", v1); double_f2(v1); $display("v1 is %0d (result) after calling double_f2(v1)", v1); v1 = 10; $display("v1 is %0d before calling double_f3(v1)", v1); double_f3(v1); $display("v1 is %0d (result) after calling double_f3(v1)", v1); end
task
task无法通过return返回结果,只能通过output,inout 或ref的参数返回;
task内可以置入耗时语句,而function不能;常见的耗时语句包括,@event、wait event、#delay等;
task 中可以调用 task 和 function, 而 function 只能调用function;
task double_t1(input int a, output int b); b = 2*a; endtask task double_t2(inout int a); a = 2*a; endtask task automatic double_t3(ref int a); a = 2*a; endtask task double_t2_delay(inout int a); a = 2*a; #10ns; endtask task automatic double_t3_delay(ref int a); a = 2*a; #10ns; endtask initial begin: int v1, v2; v1 = 10; double_t1(v1, v2); $display("v1 = %0d, double task result is %0d", v1, v2); v1 = 10; $display("v1 is %0d before calling double_t2(v1)", v1); double_t2(v1); $display("v1 is %0d (result) after calling double_t2(v1)", v1); v1 = 10; $display("v1 is %0d before calling double_t3(v1)", v1); double_t3(v1); $display("v1 is %0d (result) after calling double_t3(v1)", v1); end
inout vs ref
initial begin: inout_vs_ref int v1, v2; v1 = 10; $display("v1 is %0d before calling double_t2_delay(v1)", v1); fork double_t2_delay(v1); begin #5ns; $display("@%0t v1 = %0d in task call double_t2_delay(v1)", $time, v1); end join $display("v1 is %0d (result) after calling double_t2_delay(v1)", v1); v1 = 10; $display("v1 is %0d before calling double_t3_delay(v1)", v1); fork double_t3_delay(v1); begin #5ns; $display("@%0t v1 = %0d in task call double_t3_delay(v1)", $time, v1); end join $display("v1 is %0d (result) after calling double_t3_delay(v1)", v1); end
变量生命周期
动态: automatic
如果数据变量被声明为automatic,那么进入该进程或方法后,automatic变量会被创建,离开进程或方法后被销毁。
静态:static
全局变量伴随程序执行开始到结束,module中的变量默认情况下全部为全局变量。
static变量在仿真开始时会被创建,在进程或方法执行过程中,可以被多个进程和方法共享。
static vs automatic
对于automatic方法,其内部变量默认也是automatic,伴随automatic方法的声明周期建立和销毁。
对于static方法,其内部的所有变量默认为static类型。
无论是automatic或者static方法,可以对其内部定义的变量做单个声明。使其类型被显式声明为automatic或static。
对于static变量用户在声明是应该对齐做初始化,而初始化只会伴随他的生命周期发生一次,并不会随着方法调用被多次初始化。
module tb1; function automatic int auto_cnt(input a); int cnt =0; cnt +=a; return cnt; endfunction function static int static_cnt(input a); int cnt=0; cnt += a; return cnt; endfunction function int def_cnt(input a); int cnt=0; cnt += a; return cnt; endfunction function int def_cnt_a(input a); automatic int cnt=0; cnt += a; return cnt; endfunction initial begin $display("@1 auto_cnt=%0d", auto_cnt(1)); $display("@2 auto_cnt=%0d", auto_cnt(1)); $display("@1 static_cnt=%0d", static_cnt(1)); $display("@2 static_cnt=%0d", static_cnt(1)); $display("@1 def_cnt=%0d", def_cnt(1)); $display("@2 def_cnt=%0d", def_cnt(1)); $display("@1 def_cnt_a=%0d", def_cnt_a(1)); $display("@2 def_cnt_a=%0d", def_cnt_a(1)); end endmodule /* result @1 auto_cnt=1 @2 auto_cnt=1 @1 static_cnt=1 @2 static_cnt=2 @1 def_cnt=1 @2 def_cnt=2 @1 def_cnt_a=1 @2 def_cnt_a=1 */