Verilog中task任务的使用说明

平台:vivado2017.4

仿真:modelsin10.6d

最近在看XILINX的IP仿真时,发现他们做的仿真模型里面使用了很多task和function。这部分类容是在学习verilog期间忽略掉了。

首先来看看官方的解释。

  • Task和function说明语句

Task和function说明语句分别用来定义任务和函数。利用任务和函数可以把一个很大的程序模块分解成很多较小的任务和函数便于理解和调试。 

  • Task和function说明语句的不同点

任务和函数有些不同,主要的不同有以下四点:

  1. 函数只能与主模块共用同一个仿真时间单位,而任务可以定义自己的仿真时间单位。
  2. 函数不能启动任务,而任务能启动其它任务和函数。
  3. 函数至少要有一个输入变量,而任务可以没有或有多个任何类型的变量。
  4. 函数返回一个值,而任务则不返回值。

函数的目的是同步返回一个值来相应输入信号的值。任务却能支持多种目的。能计算多个结果值,这些结果值只能通过被调用的任务的输出或总线端口送出。Verilog模块使用函数时是把它当作表达式中的操作符,这个操作符的结果值就是这个函数的返回值。

  • Task说明语句

如果传给任务的变量值和任务完成后接收结果的变量已经定义,就可以用一条语句启动任务。任务完成以后控制就传回启动过程。如任务内部有定时控制,则启动的时间可以与控制返回的时间不同。任务可以启动其他的任务,其他任务又可以启动别的任务,可以启动的任务数是没有限制的。不管有多少任务启动,只有当所有的任务完成以后,控制才能返回。

Task语法定义:

任务:

task<任务名>;

<端口及数据类型声明语句>

<语句1>

<语句2>

...

<语句n>

endtask

任务的调用以及变量的传递

任务的调用:

<任务名>(端口1,端口2,...端口n);

在一个分频器模块中,我们来使用一个具体的例子看看怎么在模块设计中使用任务。

首先是原verilog模块为一个分频模块。模块的功能是对输入时钟100mhz信号进行分频。输出分频后时钟信号的上升沿。

// *********************************************************************************/
// Project Name :
// Author       : i_huyi
// Email        : i_huyi@qq.com
// Creat Time   : 2022/7/12 16:36:06
// File Name    : .v
// Module Name  : 
// Called By    :
// Abstract     :此模块的作用是通过寄存器来产生一个频率可调的方波。
//
//
// CopyRight(c) 2020, xxx xxx xxx Co., Ltd.. 
// All Rights Reserved
//
// *********************************************************************************/
// Modification History:
// 1. initial
// *********************************************************************************/
// *************************
// MODULE DEFINITION
// *************************
`timescale 1 ns / 1 ps
module ad_frequency#(
parameter   U_DLY = 1
                                        )
                                        (
//分频系数
input   wire[31:0]  reg_clk_div_param   ,
//产生的波形
output  reg         clk_cnv             ,
//system clk
input   wire        clk_100mhz          ,
input   wire        rst_n               
                                        );
//--------------------------------------
// localparam
//--------------------------------------

//----------------------------------------------------------------
// register define 
//----------------------------------------------------------------
reg         [31:0]  clk_cnt             ;
reg         [31:0]  clk_cnt_h           ;
reg         [31:0]  clk_cnt_l           ;
reg                 clk_cnt_odd         ;
reg                 clk_div_a           ;
reg                 clk_div_b           ;
reg                 clk_div_o           ;
reg                 clk_div_o_dly       ;


//----------------------------------------------------------------
// wire define 
//----------------------------------------------------------------

//----------------------------------------------------------------
// assignment 
//----------------------------------------------------------------

//assign ad_start    = clk_div_a || clk_div_b;
//----------------------------------------------------------------
//----------------------------------------------------------------
//奇偶分频计数器
always@(posedge clk_100mhz or negedge rst_n)
begin
        if(rst_n == 1'b0)
        begin
                clk_cnt_odd <= #U_DLY  1'b0;
                clk_cnt_h   <= #U_DLY 32'h0;
                clk_cnt_l   <= #U_DLY 32'h0;
        end
        else
        begin
                clk_cnt_odd <= #U_DLY reg_clk_div_param[0];     
                clk_cnt_h   <= #U_DLY (reg_clk_div_param >>1);
                clk_cnt_l   <= #U_DLY clk_cnt_h + clk_cnt_odd;
        end
end
//----------------------------------------------------------------
//----------------------------------------------------------------
//clk_a
always@(posedge clk_100mhz or negedge rst_n)
begin
        if(rst_n == 1'b0)
        begin
                clk_cnt     <= #U_DLY 32'h0;
                clk_div_a   <= #U_DLY 1'b0;
        end
        else if((clk_div_a == 1'b1) && (clk_cnt >= clk_cnt_h))//翻转偶数
        begin
                clk_cnt     <= #U_DLY 32'h1;
                clk_div_a   <= #U_DLY 1'b0;
        end
        else if(clk_cnt >= clk_cnt_l)//奇数个个数
        begin
                clk_cnt     <= #U_DLY 32'h1;
                clk_div_a   <= #U_DLY 1'b1;
        end
        else
        begin
                clk_cnt     <= #U_DLY clk_cnt + 32'h1;
                clk_div_a   <= #U_DLY clk_div_a;
        end
end

//----------------------------------------------------------------
//----------------------------------------------------------------
//clk_b
always@(negedge clk_100mhz or negedge rst_n)
begin
        if(rst_n == 1'b0)
                clk_div_b   <= #U_DLY 1'b0;
        else if((clk_div_a == 1'b1) && (clk_cnt_odd == 1'b1))//如果为奇数下降沿分频
                clk_div_b   <= #U_DLY 1'b1;
        else
                clk_div_b   <= #U_DLY 1'b0;
end

//----------------------------------------------------------------
//----------------------------------------------------------------
always@(posedge clk_100mhz or negedge rst_n)
begin
        if(rst_n == 1'b0)
                clk_div_o   <= #U_DLY 1'b0;
        else
                clk_div_o   <= clk_div_a || clk_div_b;
end

always@(posedge clk_100mhz or negedge rst_n)
begin
        if(rst_n == 1'b0)
                clk_div_o_dly   <= #U_DLY 1'b0;
        else
                clk_div_o_dly   <= clk_div_o;
end

always@(posedge clk_100mhz or negedge rst_n)
begin
        if(rst_n == 1'b0)
                clk_cnv    <= #U_DLY 1'b0;
        else if(clk_div_o == 1'b1 && clk_div_o_dly == 1'b0) 
                clk_cnv    <= #U_DLY 1'b1;
        else
                clk_cnv    <= #U_DLY 1'b0;
end


//----------------------------------------------------------------
//----------------------------------------------------------------

endmodule

下面是他的仿真模块。主要是看task任务语法的定义和使用。

模拟复位信号

模拟产生分频系数

创建两个任务作用分别为对输入的分频值加100,和延迟输入值那么多的时钟周期。

具体的代码如下。

`timescale 1ns / 1ps


// Company: 
// Engineer:
//
// Create Date:   14:36:04 07/28/2022
// Design Name:   ad_frequency
// Module Name:   E:/code1/xiyao/PXI_9801_FPGA_H0/9801_seq_writes/PXI_9801_seq/sources/sim/vtf_ad_frequency.v
// Project Name:  PXI_9801
// Target Device:  
// Tool versions:  
// Description: 
//
// Verilog Test Fixture created by ISE for module: ad_frequency
//
// Dependencies:
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 


module vtf_ad_frequency;

	// Inputs
	reg [31:0] reg_clk_div_param;
	reg clk_100mhz;
	reg rst_n;
	// Outputs
	wire clk_cnv;
	// Instantiate the Unit Under Test (UUT)
	ad_frequency uut (
		.reg_clk_div_param          (reg_clk_div_param          ), 
		.clk_cnv                    (clk_cnv                    ), 
		.clk_100mhz                 (clk_100mhz                 ), 
		.rst_n                      (rst_n                      )
	);

    //------------------------------------------------------
    //复位参数
    //------------------------------------------------------
    integer            i;
    //设置复位参数
    initial
    begin
            $display("[%t] : reset begin...", $realtime);
            rst_n = 0;
            for( i=0 ; i<100 ; i=i+1)
            begin
                    @(posedge clk_100mhz );
            end
            $display("[%t] : reset stop...", $realtime);
            rst_n = 1;
    end
    //------------------------------------------------------
    //分频数值
    //------------------------------------------------------
    parameter   clk_10mhz   = 10;
    parameter   clk_1mhz    = 100;
    parameter   clk_100khz  = 1000;
    parameter   delay_cnt   = 10000;

    reg [31:0]  div_value;
    reg         delay_over;

	initial 
    begin
            clk_100mhz = 0;
            wait(rst_n == 1);
            $display("[%t] : div start...", $realtime);
            //------------------------------------------------------
            //调任务
            clk_div(div_value,clk_10mhz);//调用分频值加任务
            reg_clk_div_param   = div_value;//赋值
            $display("[%t] : clk_10mhz begin...", $realtime);
            delay(delay_over,delay_cnt);//调用等待任务
            $display("[%t] : clk_10mhz end...", $realtime);
            //------------------------------------------------------
            //调任务
            clk_div(div_value,clk_1mhz);//调用分频值加任务
            reg_clk_div_param   = div_value;//赋值
            $display("[%t] : clk_1mhz begin...", $realtime);
            delay(delay_over,delay_cnt);//调用等待任务
            $display("[%t] : clk_1mhz end...", $realtime);
            //------------------------------------------------------
            //调任务
            clk_div(div_value,clk_100khz);//调用分频值加任务
            reg_clk_div_param   = div_value;//赋值
            $display("[%t] : clk_100khz begin...", $realtime);
            delay(delay_over,delay_cnt);//调用等待任务
            $display("[%t] : clk_100khz end...", $realtime);
            $finish(2);


            
	end

    //------------------------------------------------------
    //任务,输入的分频数值加100后输出
    //------------------------------------------------------
    task    clk_div;
            output  [31:0]  div_out;
            input   [31:0]  div_in;
            begin
                    repeat(10)@(posedge clk_100mhz);
                    div_out = div_in + 100;
            end
    endtask

    //------------------------------------------------------
    //任务,延时模块
    //------------------------------------------------------
    task    delay;
            output          delay_over;
            input   [31:0]  delay_in;
            begin
                    repeat(delay_in)@(posedge clk_100mhz);
                    delay_over = 1;
            end
    endtask


            


    
    always #5 clk_100mhz = ~clk_100mhz;

endmodule

仿真波形

可以看到我们定义了三个初始值,为10,100,1000调用任务模块后给到分频系数的值为110,200,1100。产生输出的cnv也不同。

另外,Verilog中function函数的使用说明,见下一篇。(15条消息) Verilog中function函数的使用说明_hy_520520的博客-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值