1.1Tasks和funcitons的不同点
Function在1个时间单位内执行完成,而task可以包含多个事件控制语句;
Function不能调用task,而task可以调用其他的task和function;
Function至少有1个input类型参数,并且不能有output或inout类型参数,task可以有任何类型和数量的参数,包括0;
Function必须有1个返回值,而task不能有返回值。
相同点:
task/function必须在module内调用
任务函数中都不能声明wire
所有输入输出都是局部寄存器?
Task function执行完成后才能返回结果
Task在被调用时,只能通过output或者inout类型参数返回结果,而function是可以在表达是中直接作为操作数,操作数的值就是函数的返回值。
例如:调用1个task或function实现将16bit word值调转顺序的功能:
Task:
Switch_bytes(old_word,new_word),将old_word的值调转顺序,然后复制给new_word;
Function:
new_word = switch_bytes (old_word),function直接作为操作数,值为返回值。
1.2 task 和task 启动:
调用task的语句应该定义好给task传递的参数值和接收task结果的输出变量。当task执行完成后,控制权应该回到启动task的进程,如果一个task中包含了时间控制语句,那么启动task的时间和返回控制权的时间可能不一致。一个task可以启动其他task,这些task又可以再启动更多的task,没有数量限制。无论启动多少task,控制权只能等待所有task完成后才能返回。
1.2.1 Task的两种声明语法:
task <automatic> task_name;
input a;
inout b;
output c;
…
e) endtask
2. task task_name (input a, inout b, output c);
a) …
b) endtask
没加automatic关键词的task都是静态task。当同时调用静态task时,task内部的item在多个程序中是共享的。动态task可以通过hierarchical name索引到。
不加automatic管检测的task都是动态task。当同时调用动态task时,task内部的item在每个调用程序中都是独立动态分配的。静态task不能通过hierarchicalname索引到。
1.2.2 task启用和参数传递
Task调用传递参数:在一个括号放置需要传递给参数的表达式列表,每个表达式用逗号隔开。如果task没有定义参数,那么就不需要传递参数。空表达式不能作为传递的参数(未赋值的变量)。
如果是传递的参数是input参数,那么这些参数求值的顺序是没定义的;如果是output/inout参数,那么这个传递给这个参数的表达式必须能够作为程序性赋值(procedural assignment)的左侧。一下参数是满足这个要求的:
reg、integer、real、realtime、time变量;
memory references;
reg、integer、time变量的串联;
memory references的串联;
reg、integer、time变量的bit选择或部分选择(一部分?)
所有的传递给task的参数的都是值,而不是参考(reference);
例子:
调用这个task:
在上面这个例子中,在my_task被调用的时候,input和inout类型的参数将会接收到调用的传递值,所以会执行以下的赋值:
a = v;
b = w;
c = x;
然后当task计算结束后,会将计算的结果值传递给output和inout参数 c、d、e,当task完成的时候将会执行以下赋值,将及结算结果返回给调用task的程序:
x = c;
y = d;
z = e;
1.2.3 task 内存使用和并发调用
同一个task可能在同一时间调用多次:
automatic task:在每一次调用时都会复制一份动态task的全部变量,以存储这次调用特定的状态值。当执行到某个调用这task程序时,应将output参数初始化为默认值,input和inout参数应该初始化为传递参数值列表的值。
(默认值:reg、time、integer类型初始化值为x;real、realtime初始化值为0.0。如果变量声明的时候就赋值了,那么初始化值为声明的这个值)
static task:静态task的所有值是静态的,只有一份在模块例化时声明的变量,在多次调用中这些变量的值都是保持不变的。Input inout output参数都应该初始化为默认值。
但是静态task在一个模块的不同的例化中的变量应该是独立存储的。
问题:static task什么时候初始化默认值?
因为automatictask的变量的值在调用结束后就会释放,所以它们不能在这个时间点之后被在某些固定结构中被引用:
它们不应使用非阻塞赋值或过程性连续赋值(proceduralcontinuous assignments)来赋值。Why?
它们不应被过程性连续赋值(procedural continuousassignments)或proceduralforce statements所引用。
它们不应被控制非阻塞赋值的intra-assignment事件所引用;?
它们不应该被系统函数追踪(traced),比如$monitor 或$ dumpvars。
1.3 task和命名blocks的disable
Disable语句提供了一种机制:在task执行完全部语句前结束task,中止循环语句,或跳过某些语句从而继续循环的另一次迭代。
如果task是嵌套的,task还调用了其他的task,那么disable这个task,它后面嵌套链上的其他task也都会disable。
如果task被disable了,那么下面活动的结果也不会指定值:
Output和inout参数;
计划的,但还没执行的非阻塞赋值;
程序性连续赋值(assign/force 语句)
在block或task中的disable语句可以去disable某个包含disable语句的block或task;
在function中的disable语句可以disable block或task,不能disable function。
例子1:block关闭它自己:
例子2:disable语句用于更早的从一个task中返回:
例子3:当a=b或循环n次后,结束break这个block。
例子4:当reset 事件发生时disable event_expr block结束,fork-join结束。
例子5:如果retrig事件在250事件单位内触发,q就一直等于1,如果间隔事件超过250,那么q=0。(retriggerable monostable 可再触发单稳态)
1.4 Function and function calling
1.4.1 Function声明
function <automatic><function_range_or_type> function_name(prot list);
…
endfuntion
function_range_or_type是可选择,如果没有指定,默认按照返回值的类型和宽度(a scalarfor the return value),如果指定了,那么这个参数指定function返回值类型:real、integer、time、realtime、指定宽度的矢量[m:n]bits;
function至少需要声明一个input;
automatic声明动态function。动态function在同时被多次调用的时候,内部的items是被动态赋值的。动态function的item不能被hierarchical参考,但是动态function可以通过hierarchical name被调用。
Function input参数的两种声明方式:
function_name后面不加(port list):
function_name后面加上(port list),port用逗号分隔:
1.4.2 从Function中返回一个值
Function在定义的时候会在function内部隐式声明一个变量,变量名和function名一致。变量类型默认式1bit reg,或者是function声明指定的类型。
在function声明的scope,或function内部再声明一个function同名的变量是非法的。
1.4.3 Function调用
function的调用是作为一个表达式中的一个操作数。
Function调用的时候,它的参数求值顺序是未定义的。(理解:多个Input参数,获得值得顺序是随机的,还是说同时调用多个function的时候,它们之间执行顺序是随机的?)。
例子:调用getbyte 函数,将结果拼接:
Word = control ? (getbyte(msbyte),getbyte(lsbyte)):0;
1.4.4 Function rules:
function不能包含有任何时间控制的语句:@、#、wait;
function 不能调用task;
function不能定义output或inout参数;
function不能含有任何非阻塞赋值,或者程序性连续赋值(force assign);
function不能含有任何事件触发。
例子:求n的阶乘:
1.4.5 常数函数(Constant function)的使用
常数函数的调用应该是调用模块本地的常量函数的函数调用,其中函数的参数是常量表达式(没读懂),常量函数是正常function的子集,遵守以下限制:
不应该包含hierical reference;
在常量函数中调用的任何函数,都应该是现有模块中的局部常量函数;
调用常量表达式(constant_expression)中允许的任何系统函数都是合法的,调用其他系统函数是非法的;
在常量函数中调用任何系统task都将被忽略;
函数中所有使用的参数都需要在调用前定义好;
所有的不是参数和function的标识符,都应该在当前函数本地定义;
任何直接或间接的被defparam语句影响的参数在function中使用,那么结果是未定义的,这将会产生错误,或常量function将会返回一个不确定值;
它们不应该声明在generate 块里;
它们本身不应该在任何需要常量expression的地方使用常量function。
常量function调用实在elaboration时间求值,它们的执行不会影响,在仿真时间或在elaboration时间多function调用中的变量初始化的值。