目录
task
任务可以包含参数声明、输入参数、输出参数、输入参数、寄存器、事件和零或多个行为语句.任务可以是static(静态的)也可以是automatic(动态的) 。静态任务为所有任务调用共享相同的存储空间,动态任务为每个任务调用分配唯一的堆叠存储空间。
SV允许:
- 在静态任务中声明动态变量,也可以在动态任务中声明静态变量;
- 声明端口的更多功能;
- 在任务结束前使用return返回;
- 通过引用、值、名称和位置传递参数值;
- 存在默认的参数值;
- 默认的参数方向是input;
- 默认的参数类型是logic;
看下面例子:
(1)在方法名的括号内部声明参数,并标明输入输出方向
module sv_task;
int x;
//task to add two integer numbers.
task sum(input int a,b,output int c);
c = a+b;
endtask
initial begin
sum(10,5,x);
$display("\tValue of x = %0d",x);
end
endmodule
(2)在方法体内部声明参数和方向
module sv_task;
int x;
//task to add two integer numbers.
task sum;
input int a,b;
output int c;
c = a+b;
endtask
initial begin
sum(10,5,x);
$display("\tValue of x = %0d",x);
end
endmodule
function
函数可以包含范围声明、返回类型声明、参数声明、输入参数声明、寄存器声明和事件声明.和任务一样,函数分为静态的和动态的。
- 没有范围或返回类型声明的函数返回一个1bit的值;
- 任何表达式都可以用作函数参数;
- 函数不能包含任何时间控制的语句,也不能调用任务;
- 函数只能返回一个值;
SV允许:
- 在静态函数中声明动态变量,也可以在动态函数中声明静态变量;
- 声明端口的更多功能;
- 在函数结束前使用return返回;
- 通过引用、值、名称和位置传递参数值;
- 存在默认的参数值;
- 默认的参数方向是input;
- 默认的参数类型是logic;
看下面例子:
(1)在函数名的括号内部声明参数
module sv_function;
int x;
//function to add two integer numbers.
function int sum(input int a,b);
sum = a+b;
endfunction
initial begin
x=sum(10,5);
$display("\tValue of x = %0d",x);
end
endmodule
(2)在函数体内部声明参数
module sv_function;
int x;
//function to add two integer numbers.
function int sum;
input int a,b;
sum = a+b;
endfunction
initial begin
x=sum(10,5);
$display("\tValue of x = %0d",x);
end
endmodule
(3)带return关键字的函数
module sv_function;
int x;
//function to add two integer numbers.
function int sum;
input int a,b;
return a+b;
endfunction
initial begin
x=sum(10,5);
$display("\tValue of x = %0d",x);
end
endmodule
(4) Void 函数,无返回值
module sv_function;
int x;
//void function to display current simulation time
function void current_time;
$display("\tCurrent simulation time is %0d",$time);
endfunction
initial begin
#10;
current_time();
#20;
current_time();
end
endmodule
(5)丢弃函数的返回值,用关键字void
module sv_function;
int x;
//function to add two integer numbers.
function int sum;
input int a,b;
return a+b;
endfunction
initial begin
$display("Calling function with void");
void'(sum(10,5));//丢弃返回值
end
endmodule
(6)函数作为表达式的一部分
module sv_function;
int x;
//function to add two integer numbers.
function int sum;
input int a,b;
return a+b;
endfunction
initial begin
x = 10 + sum(10,5);
$display("\tValue of x = %0d",x);
end
endmodule
Argument Passing 参数传递
SV提供以下几种方式将参数传递给函数和任务:
- 值传递;
- 引用传递;
- 参数名传递;
- 位置传递;
(1)值传递
在按值传递参数时,参数传递机制通过将每个参数复制到子例程区域来工作。如果对子例程中的参数有任何更改,这些更改将在子例程之外不可见。看例子:
module argument_passing;
int x,y,z;
//function to add two integer numbers.
function int sum(int x,y);
x = x+y;
return x+y;
endfunction
initial begin
x = 20;
y = 30;
z = sum(x,y);
$display("-----------------------------------------------------------------");
$display("\tValue of x = %0d",x);
$display("\tValue of y = %0d",y);
$display("\tValue of z = %0d",z);
$display("-----------------------------------------------------------------");
end
endmodule
变量x和y在函数sum中作为参数传递,sum函数中的参数x的更改在函数外部不可见。 结果如下:
(2)引用传递
在“引用传递中,原始参数的引用被传递给子例程。由于子例程的参数是指向原始参数的,在子例程内部对参数的任何改变在函数外部都可见。要表明通过引用传递的参数,参数声明的前面加关键字ref。引用传递中参数值的任何修改都可以通过在ref之前使用const关键字来避免,此时任何在子例程中更改参数值的操作都会导致编译错误。看下面例子:
module argument_passing;
int x,y,z;
//function to add two integer numbers.
function int sum(ref int x,y);//参数默认为input,且采用ref关键字后不能再加input
x = x+y;
return x+y;
endfunction
initial begin
x = 20;
y = 30;
z = sum(x,y);
$display("-----------------------------------------------------------------");
$display("\tValue of x = %0d",x);
$display("\tValue of y = %0d",y);
$display("\tValue of z = %0d",z);
$display("-----------------------------------------------------------------");
end
endmodule
函数内部对x的改变,在函数外部都是可见的,所以允许结果如下:
(3)引用传递带关键字const
引用传递中参数值的任何修改都可以通过在ref之前使用const关键字来禁止,任何在子例程中更改参数值的尝试都会导致编译错误。看下面例子:
module argument_passing;
int x,y,z;
//function to add two integer numbers.
function int sum(const ref int x,y);
x = x+y;
return x+y;
endfunction
initial begin
x = 20;
y = 30;
z = sum(x,y);
$display("-----------------------------------------------------------------");
$display("\tValue of x = %0d",x);
$display("\tValue of y = %0d",y);
$display("\tValue of z = %0d",z);
$display("-----------------------------------------------------------------");
end
endmodule
运行结果报错:
(4)默认参数值
可以为子例程的参数指定默认值。在子例程调用中,可以在参数列表中省略具有默认值的参数。如果将任何值传递给具有默认值的参数,则将考虑新值。例子如下:
module argument_passing;
int q;
//function to add three integer numbers.
function int sum(int x=5,y=10,z=20);
return x+y+z;
endfunction
initial begin
q = sum( , ,10);
$display("-----------------------------------------------------------------");
$display("\tValue of z = %0d",q);
$display("-----------------------------------------------------------------");
end
endmodule
上例中x、y、z在函数定义时都有默认值,但是也可以在进行函数调用时修改。对于使用默认值的参数,直接用空格表示;对于要修改默认值的参数,可以在对应的参数位置加入修改值。运行结果如下:
(5)通过名称传递参数
通过.参数名(函数变量)的方式传递参数,这与verilog中调用子模块类似,参数的顺序可以随意。看下面例子:
module argument_passing;
int x,y,z;
function void display(int x,string y);
$display("\tValue of x = %0d, y = %0s",x,y);
endfunction
initial begin
display(.y("Hello World"),.x(2016));
end
endmodule
运行结果:
注意,对于简单类型的变量,如:int , bit等通常没必要使用引用传递,只有当传递数组等复杂参数时才需要用到ref ,且当函数的参数同时有 简单参数和复杂参数时 ,要注意二者的顺序。看下面的例子:
task stick (ref int array [50], int a, b);
....
endtask
//a和b的方向是什么?是否采用引用传递?
//实际上这样写的话,a和b默认采用ref传递,且参数方向默认为输入
//为了避免a,b采用引用传递,可以将上面修改为:
task stick (ref int array [50],input int a, b);
....
endtask
从函数返回一个数组
verilog 的子程序只能返回一个简单值,如比特 ,整数或者是向量;但是在SV 中,函数可以通过多种方式返回一个数组。第一种就是定义一个数组类型,然后在函数的声明中使用该类型。
typedef int fixed_array [5];
fixed_array f5;
function fixed_array init(int start);
foreach (init[i])
init[i] = i + start;
endfunction
initial begin
f5 = init(5);
foreach(f5[i])
$display("f5[%0d] = %0d", i, f5[i]);
end
上述代码存在的一个问题是,函数init创建了一个数组,该数组值被拷贝到f5中,如果数组很大,可能会引起一个性能上的问题。
另一种方法就是通过引用传递关键字ref来进行数组参数的传递。
function void init(ref int f [5], input int start);
foreach (f[i])
f[i] = i + start;
endfunction
int fa [5];
initial begin
init(fa, 5);
foreach (fa[i])
$display("fa[%0d] = %0d", i, fa[i]);
end
Loops
SV提供不同类型的循环语句:
forever | Runs the given set of statements forever |
repeat | Repeats the given set of statements for a given number of times |
while | Repeats the given set of statments as long as given condition is true |
for | Similar to while loop, but more condense and popular form |
do while | Repeats the given set of statements atleast once, and then loops as long as condition is true |
foreach | Used mainly to iterate through all elements in an array |
forever
类似于while(1),如果不添加终止循环的语句,它会一直执行。
module tb;
// This initial block has a forever loop which will "run forever"
// Hence this block will never finish in simulation
initial begin
forever begin
#5 $display ("Hello World !");
end
end
// Because the other initial block will run forever, our simulation will hang!
// To avoid that, we will explicity terminate simulation after 50ns using $finish
initial
#50 $finish;//终止循环
endmodule
仿真结果:
Simulation Log
ncsim> run
Hello World !
Hello World !
Hello World !
Hello World !
Hello World !
Hello World !
Hello World !
Hello World !
Hello World !
Simulation complete via $finish(1) at time 50 NS + 0
repeat
module tb;
// This initial block will execute a repeat statement that will run 5 times and exit
initial begin
// Repeat everything within begin end 5 times and exit "repeat" block
repeat(5) begin
$display ("Hello World !");
end
end
endmodule
仿真结果:
ncsim> run
Hello World !
Hello World !
Hello World !
Hello World !
Hello World !
ncsim: *W,RNQUIE: Simulation is complete.
while
module tb;
bit clk;
always #10 clk = ~clk;
initial begin
bit [3:0] counter;
$display ("Counter = %0d", counter); // Counter = 0
while (counter < 10) begin
@(posedge clk);//在while语句块中不需要加always关键字,在其他块语句中也不需要加,语句末需要加分号,这是与always语句的不同
counter++;
$display ("Counter = %0d", counter); // Counter increments
end
$display ("Counter = %0d", counter); // Counter = 10
$finish;//需要加上终止循环的语句,否则clk会一直运行
end
endmodule
仿真结果:
ncsim> run
Counter = 0
Counter = 1
Counter = 2
Counter = 3
Counter = 4
Counter = 5
Counter = 6
Counter = 7
Counter = 8
Counter = 9
Counter = 10
Counter = 10
Simulation complete via $finish(1) at time 190 NS + 0
for
module tb;
bit clk;
always #10 clk = ~clk;
initial begin
bit [3:0] counter;
$display ("Counter = %0d", counter); // Counter = 0
for (counter = 2; counter < 14; counter = counter + 2) begin
@(posedge clk);
$display ("Counter = %0d", counter); // Counter increments
end
$display ("Counter = %0d", counter); // Counter = 14
$finish;
end
endmodule
仿真结果:
ncsim> run
Counter = 0
Counter = 2
Counter = 4
Counter = 6
Counter = 8
Counter = 10
Counter = 12
Counter = 14
Simulation complete via $finish(1) at time 110 NS + 0
do while
与while的不同之处在于do while是先执行后检查,所以执行次数总是比while多一次。
module tb;
bit clk;
always #10 clk = ~clk;
initial begin
bit [3:0] counter;
$display ("Counter = %0d", counter); // Counter = 0
do begin
@ (posedge clk);
counter ++;
$display ("Counter = %0d", counter); // Counter increments
end while (counter < 5);
$display ("Counter = %0d", counter); // Counter = 14
$finish;
end
endmodule
仿真结果:
ncsim> run
Counter = 0
Counter = 1
Counter = 2
Counter = 3
Counter = 4
Counter = 5
Counter = 5
Simulation complete via $finish(1) at time 90 NS + 0
foreach
foreach是for语句的精简版,不需要定义自增变量,以便用于遍历数组。
module tb_top;
bit [7:0] array [8]; // Create a fixed size array
initial begin
// Assign a value to each location in the array
foreach (array [index]) begin
array[index] = index;
end
// Iterate through each location and print the value of current location
foreach (array [index]) begin
$display ("array[%0d] = 0x%0d", index, array[index]);
end
end
endmodule
仿真结果:
ncsim> run
array[0] = 0x0
array[1] = 0x1
array[2] = 0x2
array[3] = 0x3
array[4] = 0x4
array[5] = 0x5
array[6] = 0x6
array[7] = 0x7
ncsim: *W,RNQUIE: Simulation is complete.
break和continue
两个关键字的作用和C语言相同,前者用于终止循环,后者用于终止本次循环进入下一次循环。
module tb;
initial begin
// This for loop increments i from 0 to 9 and exit
for (int i = 0 ; i < 10; i++) begin
$display ("Iteration [%0d]", i);
// Let's create a condition such that the
// for loop exits when i becomes 7
if (i == 7)
break;
end
end
endmodule
仿真结果:
ncsim> run
Iteration [0]
Iteration [1]
Iteration [2]
Iteration [3]
Iteration [4]
Iteration [5]
Iteration [6]
Iteration [7]
ncsim: *W,RNQUIE: Simulation is complete.
module tb;
initial begin
// This for loop increments i from 0 to 9 and exit
for (int i = 0 ; i < 10; i++) begin
// Let's create a condition such that the
// for loop
if (i == 7)
continue;
$display ("Iteration [%0d]", i);
end
end
endmodule
ncsim> run
Iteration [0]
Iteration [1]
Iteration [2]
Iteration [3]
Iteration [4]
Iteration [5]
Iteration [6]
Iteration [8]
Iteration [9]
ncsim: *W,RNQUIE: Simulation is complete.