Verilog 中 task 的语法,及使用 task 来完成模块的 testbench

本文阐述了 Verilog 中 task 的语法,并使用 task 完成了样例模块 testbench 的编写。...
摘要由CSDN通过智能技术生成

概述

Verilog 中的 task 是一种不可综合的语法,它既提供了从不同位置执行公共过程的能力(因为这样可以实现代码共享),也提供了把大过程切分成小过程的能力(因为小过程更便于阅读和调试)。相较于 function, task 的 input 和 output 是可选项,同时其中也可以包含延迟控制语句,常被用在 testbench 中。

task 的语法

task的使能,就是从一条包含有传进去的参数和用于接受结果的变量的调用语句,控制从调用的过程转到 task。当 task 完成的时候,控制再传回调用的过程。所以如果 task 包含时序控制的语句,那么调用 task 的时间和退出 task 的时间可以是不一样的。 task 可以再使能(调用)其他 task,没有数量的限制。

task 声明的语法如下:

task [automatic] task_name (
	port_declaration port_name, port_name, ... ,
	port_declaration port_name, port_name, ... );
	local variable declarations
	procedural_statement or statement_group
endtask

序列检测模块

只要理解了 task 的用法,我们就可以自然而然地把它用到各种模块的 testbench 编写中。

下面是一个检测“10110”序列的模块,在检测到后令 detected = 1.

`timescale 1ns / 1ns

module detector
(
 input clk ,
 input rst_n ,
 input data ,
 output reg detected
);

localparam IDLE = 3'b000 ,
             S0 = 3'b001 ,
             S1 = 3'b010 ,
             S2 = 3'b011 ,
             S3 = 3'b100 ,
             S4 = 3'b101 ;

reg [2:0] current_state, next_state;

always@ (posedge clk or negedge rst_n)
begin
  if(!rst_n)
    current_state <= IDLE;
  else
    current_state <= next_state;
end

always@ (*)
begin
  case(current_state)
    IDLE: begin
      detected = 0;
      if(data == 0)
        next_state = IDLE;
      else
        next_state = S0;
    end
    S0: begin
      detected = 0;
      if(data == 0)
        next_state = S1;
      else
        next_state = S0;
    end
    S1: begin
      if(data == 0)
        next_state = IDLE;
      else
        next_state = S2;
    end
    S2: begin
      if(data == 0)
        next_state = IDLE;
      else
        next_state = S3;
    end
    S3: begin
      if(data == 0)
        next_state = S4;
      else
        next_state = S0;
    end
    S4: begin
      detected = 1;
      if(data == 0)
        next_state = IDLE;
      else
        next_state = S0;
    end
  endcase
end

endmodule

testbench

使用 task,我们可以便捷地实现激励信号的输入。下面展示了序列检测器的 testbench。

`timescale 1ns / 1ps

module tb_detector;
parameter PERIOD = 2;
reg clk, rst_n, data;
wire detected;

detector d1(.clk(clk), .rst_n(rst_n), .data(data), .detected(detected));

reg [4:0] buffer;
integer i;
task series_gen(input [4:0] series);
  buffer = series;
  for(i = 4; i >= 0; i = i - 1) begin
    @(negedge clk)
      data = buffer[i];
  end
endtask

initial begin
  clk = 0;
  rst_n = 0;
  @(negedge clk)
  rst_n = 1;
  series_gen(5'b10110);
  series_gen(5'b10111);
end

always begin
  #(PERIOD / 2) clk = ~clk;
end

endmodule

仿真波形显示正确地产生了激励。
激励产生

在定义了产生激励信号的 series_gen task之后,每次需要产生激励信号时,我们只需要向这个 task 中填入参数就可以了,真是便捷啊。

  • 14
    点赞
  • 75
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
Verilogtask是一种用户自定义的可重用代码块,它可以接受传递的参数和返回值。task可以把复杂的代码分解成更小的可维护的部分。下面是task使用方法: 1. 定义task 使用task可以定义一个用户自定义的代码块,它可以接受传递的参数和返回值。task语法格式如下: ``` task task_name(input [parameter_range] parameter_name, ...); //task body endtask ``` 其task_name为task的名称,parameter_name为task的参数名,parameter_range为参数的位宽和类型,可以是常量、变量或者其他参数。 2. 调用task 使用task时,需要先声明task并传递参数,然后使用task名称进行调用。task的调用格式如下: ``` task_name(parameter_value, ...); ``` 其,parameter_value是传递给task的参数值。 下面是一个简单的例子,演示如何使用task来实现一个简单的计算器: ``` module calculator( input [7:0] A, input [7:0] B, output [7:0] result ); task add(input [7:0] a, input [7:0] b, output [7:0] sum); sum = a + b; endtask task sub(input [7:0] a, input [7:0] b, output [7:0] diff); diff = a - b; endtask reg [7:0] add_result, sub_result; initial begin add(A, B, add_result); sub(A, B, sub_result); $display("A + B = %d", add_result); $display("A - B = %d", sub_result); end endmodule ``` 在这个例子,我们定义了两个task,一个用于加法运算,一个用于减法运算。在初始块,我们调用了这两个task,传递了参数,并把结果存储在两个寄存器。最后,我们使用$display函数来显示计算结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值