verilog语言中任务和函数的区别
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了verilog语言中任务和函数的区别相关的知识,希望对你有一定的参考价值。
任务和函数有助于简化程序,有点类似与Fortran语言的subroutine和function。任务和函数的共同点:
1.任务和函数必须在模块内定义,其作用范围仅适用于该模块,可以在模块内多次调用。
2.任务和函数中可以声明局部变量,如寄存器,时间,整数,实数和事件,但是不能声明线网类型的变量。
3.任务和函数中只能使用行为级语句,但是不能包含always和initial块,设计者可以在always和initial块中调用任务和函数。
任务和函数的不同点:
函数 任务
函数能调用另一个函数,但是不能调用任务 任务可以调用另一个任务,也可以调用函数
函数总是在仿真时刻0开始 任务可以在非零时刻开始执行
函数一定不能包含任何延迟,事件或者时序控制声明语句 任务可以包含延迟,事件或者时序控制声明语句
函数至少要有一个输入变量,也可以有多个输入变量 任务可以没有或者有多个输入,输出,输入输出变量
函数只能返回一个值,函数不能有输出或者双向变量 任务不返回任何值,或者返回多个输出或双向变量值
由上述的特点决定:函数用于替代纯组合逻辑的verilog代码,而任务可以代替verilog的任何代码。
8.2任务
任务使用关键字task和endtask来进行声明,如果子程序满足下面任何一个条件,则必须使用任务而不能使用函数。
1.子程序中包含有延迟,时序或者事件控制结构
2.没有输出或者输出变量超过一个
3.没有输入变量
例:
module operation;
parameter delay=10;
reg [15:0] A,B, AB_AND,AB_OR,AB_XOR;
always @(A or B)
begin
bitwise_ope(AB_AND,AB_OR,AB_XOR,A,B);
end
task bitwise_oper;
output [15:0] ab_and,ab_or,ab_xor;
input [15:0] a,b;
begin
#delay ab_and=a&b;
ab_or=a|b;
ab_xor=a^b;
end
endtask
always @(posedge clk)
bitwise_xor(ef_xor,e,f);
always @(posedege clk2)
bitwise_xor(cd_xor,c,d)
task autumatic bitwise_xor;
output ab_xor;
input a,b;
begin
ab_xor=a^b;
end
endtask
endmodule
自动(可重入)任务:verilog任务中所有声明的变量地址空间都是静态分配的,因此如果在一个模块中多次调用任务时,可能会造成地址空间的冲突,为了避免这个问题,verilog通过在task关键字后面添加automatic使任务称为可重入的,这时在调用任务时,会自动给任务声明变量分配动态地址空间,这样有效避免了地址空间的冲突。
8.3 函数
函数使用关键字function和endfunction定义,对于子程序,如果满足下述所有条件则可以用函数来完成:
1.在子程序中不含有延迟时序或者控制结构
2.子程序只有一个返回值
3.至少有一个输入变量
4.没有输出或者双向变量
5.不含有非阻塞赋值语句
例:
module parity;
reg [31:0] addr;
reg parity;
always @(addr)
begin
parity=calc_parity(addr);
end
function calc_parity;
input [31:0] addr;
begin
calc_parity=^addr;
end
endfunction
endmodule
跟任务调用一样,在模块中如果调用多次函数,也会碰到地址冲突的问题,因此也引入automatic关键字来对函数可重用性声明。没有进行可重用性声明的函数不可以多次或者递归调用,进行了可重用性声明的函数可以递归调用。
常量函数和带符号函数(函数声明时加signed关键字说明)
module ram;
parameter RAM_DEPTH=256;
input [clogb2(RAM_DEPTH)-1:0] addr;//clogb2函数返回值为8
function integer clogb2(input integer depth);
begin
for(clogb2=0; depth>0;clogb2=clogb2+1)
depth=depth>1;
end
endfunction
endmodule
练习:用两种不同的方法设计一个功能相同的模块,完成4个8位2进制输入数据的冒泡排序。第一种,用纯组合逻辑实现;第二种,假设8位数据按照时钟节拍串行输入,要求时钟触发任务的执行,每个时钟周期完成一次数据交换的操作。
//----------------- 第一种 ------------------
module sort4(ra,rb,rc,rd,a,b,c,d);
output[7:0] ra,rb,rc,rd;
input[7:0] a,b,c,d;
reg[7:0] ra,rb,rc,rd;
reg[7:0] va,vb,vc,vd;
always @ (a or b or c or d)
begin
va,vb,vc,vd=a,b,c,d;
change(va,vb);
change(vb,vc);
change(vc,vd);
change(va,vb);
change(vb,vc);
change(va,vb);
ra,rb,rc,rd=va,vb,vc,vd;
end
task change; //make a task of comparing
inout[7:0] x,y;
reg[7:0] tmp;
if(x>y)
begin
tmp=x;
x=y;
y=tmp;
end
endtask
endmodule
//----------------- 第二种 ------------------
module sort4(clk,reset,ra,rb,rc,rd,a);
output[7:0] ra,rb,rc,rd;
input[7:0] a;
input clk,reset;
reg[7:0] ra,rb,rc,rd;
reg[7:0] va,vb,vc,vd;
always @ (posedge clk)
begin
if(!reset)
begin
va<=0;vb<=0;vc<=0;vd<=0;
end
else
va<=a;
end
always @ (posedge clk)
begin
change(va,vb);
change(vb,vc);
change(vc,vd);
change(va,vb);
change(vb,vc);
change(va,vb);
ra,rb,rc,rd=va,vb,vc,vd;
end
task change; //make a task of comparing
inout[7:0] x,y;
reg[7:0] tmp;
if(x>y)
begin
tmp=x;
x=y;
y=tmp;
end
endtask
endmodule 参考技术A 任务可以有input、output和inout,数量不限,函数只有input参数,且至少有一个input;
任务可以包含有时序控制(如延时等),函数不能包含有任何延迟,仿真时间为0;
任务可以用disable中断,函数不允许disable、wait语句;
任务可以通过I/O端口实现值传递,函数名即输出变量名,通过函数返回值;
任务可以调用其他任务和函数,函数只能调用其他函数,不能调用任务;
任务可以定义自己的仿真时间单位,函数只能与主模块共用一个仿真时间单位;
函数通过一个返回一个值来响应输入信号的值,任务却能支持多种目的,能计算多个结果值,结果值只能通过被调用的任务的输出端口输出或总线端口送出;
另外在函数中不能有wire型变量.
任务定义语法:
task <任务名>;
<端口及数据类型声明语句>
<语句1>......
endtask
函数定义的语法:
function <返回值类型或范围>(函数名)
<端口说明语句>
<变量类型说明语句>
begin
<语句>......
end
endfunction
从百度搜,有很多相关介绍 参考技术B 分呢? 哈哈!书本p114本回答被提问者采纳
Verilog语言中casecasexcasez的用法和区别
Verilog语言中case、casex、casez的用法和区别
casez与casex语句是case语句的两种变体, 在写testbench时用到。
一、case、casex、casez的区别
下表给出case、casex、casez的真值表:
-
在case语句中,敏感表达式中与各项值之间的比较是一种全等比较,每一位都相同才认为匹配。
-
在casez语句中,如果分支表达式某些位的值为高阻z,那么对这些位的比较就会忽略,不予考虑,而只关注其他位的比较结果。
-
在casex语句中,则把这种处理方式进一步扩展到对x的处理,即如果比较双方有一方的某些位的值是z或x,那么这些位的比较就不予考虑。
二、case/casez/casex 在simulation/synthesis的区别
有的网上说casex和casez属于不可综合语句,这是针对一般电路不会出现x状态来说的,但是综合工具并不会对x,z认识这个状态,所以综合出来的电路是一样的。
- 使用过程中许需要注意的问题:
1)一般经常使用到的是casez语句,最好少用casex
2)case/casez/casex其实都是可综合的
3)在电路中,可以用?来表示无关值的z
4)case的描述,匹配都是从上到下进行的 - 仿真的不同
1)对于case
case (sel)
2'b00: y = a;
2'b01: y = b;
2'bx0: y = c;
2'b1x: y = d;
2'bz0: y = e;
2'b1?: y = f;
default : y = g;
endcase
对于case来说,每一种情况都会识别(1/0/z/x)
当sel的状态是一下情况时,会出现以下结果
sel | y | case item |
---|---|---|
00 | a | 00 |
11 | g | default |
xx | g | default |
x0 | c | x0 |
1z | f | 1? |
z1 | g | default |
2)对于casez
casez (sel)
2'b00: y = a;
2'b01: y = b;
2'bx0: y = c;
2'b1x: y = d;
2'bz0: y = e;
2'b1?: y = f;
default: y = g;
endcase
首先,case的描述,匹配都是从上到下进行的,如果使用了casez,看上面的casez的列表,只要输入有z/?的话,就能和任意匹配。
sel | y | case item |
---|---|---|
00 | a | 00 |
11 | f | 1? |
xx | g | default |
x0 | c | x0 (或者z0) |
1z | d | 1x(或者1?/z0) |
z1 | b | 01(或者1?) |
3)对于casex
casex (sel)
2'b00 : y = a;
2'b01 : y = b;
2'bx0 : y = c;
2'b1x : y = d;
2'bz0 : y = e;
2'b1? : y = f;
default : y = g;
endcase
casex也是从上到下匹配,当出现x/z/?的输入的时候,都不会care,只管不是大大情况来匹配
sel | y | case item |
---|---|---|
00 | a | 00 |
11 | d | 1x(或者1?) |
xx | a | 00(或者1?) |
x0 | a | 00 (或者x0/1x/z0/1?) |
1z | c | x0(或者1x/z0/1?) |
z1 | b | 01(或者1x/1?) |
- 综合的不同
综合的时候,因为综合工具其实都不会管你什么x/z/?,对于综合工具来说是一样的,所以case/casez/casex不同写法的综合结果,例子都是同样的。
例一:
case (sel)
2'b00 : mux_out = mux_in[0];
2'b01 : mux_out = mux_in[1];
2'b1? : mux_out = mux_in[2];
default : mux_out = mux_in[3];
endcase
例二:
case (sel)
2'b00 : mux_out = mux_in[0];
2'b01 : mux_out = mux_in[1];
2'b1x : mux_out = mux_in[2];
default : mux_out = mux_in[3];
endcase
这俩个例子的结果是一样的。
case(不是casez/casex的时候)的列表里面的x和z,都被综合工具认为是不可达到的状态就被去掉了。casez和casex里面的x/z都被认为是don’t care。
- 对于综合、仿真的结果
1)在实际写代码的时候,如果使用case的时候,尽量不要用x/z/?,综合工具也会不care
2)casez和casex综合的结果是一致的。
3)casez稍好用一些,因为它可以用来代表don’t care的值
4)最重要的一点就是,casez和casex其实没有孰优孰劣
5)casez语句用来处理不考虑高阻值z的比较过程,casex语句则将高阻值z和不定值都视为不必关心的情况。所谓不必关心的情况,即在表达式进行比较时,不将该位的状态考虑在内。这样在case语句表达式进行比较时,就可以灵活地设置以对信号的某些位进行比较。
以上是关于verilog语言中任务和函数的区别的主要内容,如果未能解决你的问题,请参考以下文章