Verilog task使用说明
创始人
2024-04-05 10:21:57
0

任务与函数的区别

和函数一样,任务(task)可以用来描述共同的代码段,并在模块内任意位置被调用,让代码更加的直观易读。函数一般用于组合逻辑的各种转换和计算,而任务更像一个过程,不仅能完成函数的功能,还可以包含时序控制逻辑。下面对任务与函数的区别进行概括:

比较点函数任务
输入函数至少有一个输入,端口声明不能包含 inout 型任务可以没有或者有多个输入,且端口声明可以为 inout 型
输出函数没有输出任务可以没有或者有多个输出
返回值函数至少有一个返回值

任务没有返回值

仿真时刻函数总在零时刻就开始执行任务可以在非零时刻执行
时序逻辑函数不能包含任何时序控制逻辑任务不能出现 always 语句,但可以包含其他时序控制,如延时语句
调用函数只能调用函数,不能调用任务任务可以调用函数和任务
书写规范函数不能单独作为一条语句出现,只能放在赋值语言的右端任务可以作为一条单独的语句出现语句块中

任务

任务声明

任务在模块中任意位置定义,并在模块内任意位置引用,作用范围也局限于此模块。

模块内子程序出现下面任意一个条件时,则必须使用任务而不能使用函数。

  • 1)子程序中包含时序控制逻辑,例如延迟,事件控制等
  • 2)没有输入变量
  • 3)没有输出或输出端的数量大于 1

Verilog 任务声明格式如下:

task       task_id ;port_declaration ;procedural_statement ;
endtask

        任务中使用关键字 input、output 和 inout 对端口进行声明。input 、inout 型端口将变量从任务外部传递到内部,output、inout 型端口将任务执行完毕时的结果传回到外部。进行任务的逻辑设计时,可以把 input 声明的端口变量看做 wire 型,把 output 声明的端口变量看做 reg 型。但是不需要用 reg 对 output 端口再次说明。对 output 信号赋值时也不要用关键字 assign。为避免时序错乱,建议 output 信号采用阻塞赋值。

例如,一个带延时的异或功能 task 描述如下:

task xor_oper_iner;input [N-1:0]   numa;input [N-1:0]   numb;output [N-1:0]  numco ;//output reg [N-1:0]  numco ; //无需再注明 reg 类型,虽然注明也可能没错#3  numco = numa ^ numb ;//assign #3 numco = numa ^ numb ; //不用assign,因为输出默认是reg
endtask

任务在声明时,也可以在任务名后面加一个括号,将端口声明包起来。

上述设计可以更改为:

task xor_oper_iner(input [N-1:0]   numa,input [N-1:0]   numb,output [N-1:0]  numco  ) ;#3  numco       = numa ^ numb ;
endtask

任务调用

任务可单独作为一条语句出现在 initial 或 always 块中,调用格式如下:

task_id(input1, input2, …,outpu1, output2, …);

        任务调用时,端口必须按顺序对应。输入端连接的模块内信号可以是 wire 型,也可以是 reg 型。输出端连接的模块内信号要求一定是 reg 型,这点需要注意。

对上述异或功能的 task 进行一个调用,完成对异或结果的缓存。

module xor_oper#(parameter         N = 4)(input             clk ,input             rstn ,input [N-1:0]     a ,input [N-1:0]     b ,output [N-1:0]    co  );reg [N-1:0]          co_t ;always @(*) begin          //任务调用xor_oper_iner(a, b, co_t);endreg [N-1:0]          co_r ;always @(posedge clk or negedge rstn) beginif (!rstn) beginco_r   <= 'b0 ;endelse beginco_r   <= co_t ;         //数据缓存endendassign       co = co_r ;/*------------ task -------*/task xor_oper_iner;input [N-1:0]   numa;input [N-1:0]   numb;output [N-1:0]  numco ;#3  numco       = numa ^ numb ;   //阻塞赋值,易于控制时序endtaskendmodule

对上述异或功能设计进行简单的仿真,testbench 描述如下。

激励部分我们使用简单的 task 进行描述,激励看起来就更加的清晰简洁。

其实,task 最多的应用场景还是应用于 testbench 中进行仿真。task 在一些编译器中也不支持综合。

`timescale 1ns/1nsmodule test ;reg          clk, rstn ;initial beginrstn      = 0 ;#8 rstn   = 1 ;forever beginclk = 0 ; # 5;clk = 1 ; # 5;endendreg  [3:0]   a, b;wire [3:0]   co ;initial begina         = 0 ;b         = 0 ;sig_input(4'b1111, 4'b1001, a, b);sig_input(4'b0110, 4'b1001, a, b);sig_input(4'b1000, 4'b1001, a, b);endtask sig_input ;input [3:0]       a ;input [3:0]       b ;output [3:0]      ao ;output [3:0]      bo ;@(posedge clk) ;ao = a ;bo = b ;endtask ; // sig_inputxor_oper         u_xor_oper(.clk              (clk  ),.rstn             (rstn ),.a                (a    ),.b                (b    ),.co               (co   ));initial beginforever begin#100;if ($time >= 1000)  $finish ;endendendmodule // test

任务操作全局变量

        因为任务可以看做是过程性赋值,所以任务的 output 端信号返回时间是在任务中所有语句执行完毕之后。任务内部变量也只有在任务中可见,如果想具体观察任务中对变量的操作过程,需要将观察的变量声明在模块之内、任务之外,可谓之"全局变量"。

例如有以下 2 种尝试利用 task 产生时钟的描述方式。

//way1 to decirbe clk generating, not work
task clk_rvs_iner ;output    clk_no_rvs ;# 5 ;     clk_no_rvs = 0 ;# 5 ;     clk_no_rvs = 1 ;
endtask
reg          clk_test1 ;
always clk_rvs_iner(clk_test1);//way2: use task to operate global varialbes to generating clk
reg          clk_test2 ;
task clk_rvs_global ;# 5 ;     clk_test2 = 0 ;# 5 ;     clk_test2 = 1 ;
endtask // clk_rvs_iner
always clk_rvs_global;

automatic 任务

        和函数一样,Verilog 中任务调用时的局部变量都是静态的。可以用关键字 automatic 来对任务进行声明,那么任务调用时各存储空间就可以动态分配,每个调用的任务都各自独立的对自己独有的地址空间进行操作,而不影响多个相同任务调用时的并发执行。如果一任务代码段被 2 处及以上调用,一定要用关键字 automatic 声明。

当没有使用 automatic 声明任务时,任务被 2 次调用,可能出现信号间干扰,例如下面代码描述:

task test_flag ;input [3:0]       cnti ;input             en ;output [3:0]      cnto ;if (en) cnto = cnti ;
endtaskreg          en_cnt ;
reg [3:0]    cnt_temp ;
initial beginen_cnt    = 1 ;cnt_temp  = 0 ;#25 ;     en_cnt = 0 ;
end
always #10 cnt_temp = cnt_temp + 1 ;reg [3:0]             cnt1, cnt2 ;
always @(posedge clk) test_flag(2, en_cnt, cnt1);       //task(1)
always @(posedge clk) test_flag(cnt_temp, !en_cnt, cnt2);//task(2)

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
客厅放八骏马摆件可以吗(家里摆... 今天给各位分享客厅放八骏马摆件可以吗的知识,其中也会对家里摆八骏马摆件好吗进行解释,如果能碰巧解决你...
苏州离哪个飞机场近(苏州离哪个... 本篇文章极速百科小编给大家谈谈苏州离哪个飞机场近,以及苏州离哪个飞机场近点对应的知识点,希望对各位有...