【Verilog 教程】6.2Verilog任务

news2024/11/25 2:19:53

关键词:任务
任务与函数的区别

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

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

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

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);
    end
 
    reg [N-1:0]          co_r ;
    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            co_r   <= 'b0 ;
        end
        else begin
            co_r   <= co_t ;         //数据缓存
        end
    end
    assign       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 ;   //阻塞赋值,易于控制时序
    endtask
 
endmodule

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

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

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

`timescale 1ns/1ns
 
module test ;
    reg          clk, rstn ;
 
    initial begin
        rstn      = 0 ;
        #8 rstn   = 1 ;
        forever begin
            clk = 0 ; # 5;
            clk = 1 ; # 5;
        end
    end
 
    reg  [3:0]   a, b;
    wire [3:0]   co ;
    initial begin
        a         = 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);
    end
 
    task 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_input
 
    xor_oper         u_xor_oper
    (
      .clk              (clk  ),
      .rstn             (rstn ),
      .a                (a    ),
      .b                (b    ),
      .co               (co   ));
 
    initial begin
        forever begin
            #100;
            if ($time >= 1000)  $finish ;
        end
    end
 
endmodule // test

仿真结果如下。

由图可知,异或输出逻辑结果正确,相对于输入有 3ns 的延迟。

且连接信号 a,b,co_t 与任务内部定义的信号 numa,numb,numco 状态也保持一致。
在这里插入图片描述
任务操作全局变量
因为任务可以看做是过程性赋值,所以任务的 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;

仿真结果如下。

第一种描述方式,虽然任务内部变量会有赋值 0 和赋值 1 的过程操作,但中间变化过程并不可见,最后输出的结果只能是任务内所有语句执行完毕后输出端信号的最终值。所以信号 clk_test1 值恒为 1,此种方式产生不了时钟。

第二种描述方式,虽然没有端口信号,但是直接对"全局变量"进行过程操作,因为该全局变量对模块是可见的,所以任务内信号翻转的过程会在信号 clk_test2 中体现出来。
在这里插入图片描述
automatic 任务
和函数一样,Verilog 中任务调用时的局部变量都是静态的。可以用关键字 automatic 来对任务进行声明,那么任务调用时各存储空间就可以动态分配,每个调用的任务都各自独立的对自己独有的地址空间进行操作,而不影响多个相同任务调用时的并发执行。

如果一任务代码段被 2 处及以上调用,一定要用关键字 automatic 声明。

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

task test_flag ;
        input [3:0]       cnti ;
        input             en ;
        output [3:0]      cnto ;
        if (en) cnto = cnti ;
endtask

reg          en_cnt ;
reg [3:0]    cnt_temp ;
initial begin
        en_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)

仿真结果如下。

en_cnt 为高时,任务 (1) 中信号 en 有效, cnt1 能输出正确的逻辑值;

此时任务 (2) 中信号 en 是不使能的,所以 cnt2 的值被任务 (1) 驱动的共用变量 cnt_temp 覆盖。

en_cnt 为低时,任务 (2) 中信号 en 有效,所以任务 (2) 中的信号 cnt2 能输出正确的逻辑值;而此时信号 cnt1 的值在时钟的驱动下,一次次被任务 (2) 驱动的共用变量 cnt_temp 覆盖。

可见,任务在两次并发调用中,共用存储空间,导致信号相互间产生了影响。
在这里插入图片描述
其他描述不变,只在上述 task 声明时加入关键字 automatic,如下所以。

task automatic test_flag ;

此时仿真结果如下。

en_cnt 为高时,任务 (1) 中信号 cnt1 能输出正确的逻辑值,任务 (2) 中信号 cnt2 的值为 X;
en_cnt 为低时,任务 (2) 中信号 cnt2 能输出正确的逻辑值,任务 (1) 中信号 cnt1 的值为 X;
可见,任务在两次并发调用中,因为存储空间相互独立,信号间并没有产生影响。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1048721.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

win10搭建Selenium环境+java+IDEA(2)

接着上一个搭建环境开始叙述&#xff1a;win10系统x64安装java环境以及搭建自动化测试环境_荟K的博客-CSDN博客 上一步结尾的浏览器驱动&#xff0c;本人后面改到了谷歌浏览器.exe文件夹下&#xff1a; 这里需要注意&#xff0c;这个新路径要加载到系统环境变量中。 上一步下…

2023-9-28 JZ26 树的子结构

题目链接&#xff1a;树的子结构 import java.util.*; /** public class TreeNode {int val 0;TreeNode left null;TreeNode right null;public TreeNode(int val) {this.val val;}} */ public class Solution {public boolean HasSubtree(TreeNode root1,TreeNode root2) …

吉利微型纯电,5 万元的快乐

熊猫骑士作为一款主打下层市场的迷你车型&#xff0c;吉利熊猫骑士剑指宝骏悦也&#xff0c;五菱宏光 MINI 等热门选手。 9 月 15 日&#xff0c;吉利熊猫骑士正式上市&#xff0c;售价为 5.39 万&#xff0c;限时优享价 4 .99 万元。价格和配置上对这个级别定位的战略车型有一…

力扣刷题-哈希表-判断两个字符串_其他中元素是否一致

242 有效的字母异位词 给定两个字符串 s 和 t &#xff0c;编写一个函数来判断 t 是否是 s 的字母异位词。 示例 1: 输入: s “anagram”, t “nagaram” 输出: true 示例 2: 输入: s “rat”, t “car” 输出: false 说明: 你可以假设字符串只包含小写字母。 解释&#x…

云安全之身份认证与授权机制介绍

认证与授权技术概述 认证&#xff0c;用于证实某事是否真实或有效的过程。认证一般由标识(ldentification)和鉴别(Authentication)两部分组成。 认证技术分类 身份认证&#xff1a;口令认证、生物特征识别 报文认证&#xff1a;报文源的认证、报文宿的认证、报文内容的认证…

网络爬虫--伪装浏览器

从用户请求的Headers反反爬 在访问某些网站的时候&#xff0c;网站通常会用判断访问是否带有头文件来鉴别该访问是否为爬虫&#xff0c;用来作为反爬取的一种策略。很多网站都会对Headers的User-Agent进行检测&#xff0c;还有一部分网站会对Referer进行检测&#xff08;一些资…

MQ - 34 基础功能:在消息队列内核中支持WebSocket的设计

文章目录 导图概述WebSocket 是什么双工(双向)通信特点和应用场景客户端使用示例WebSocket 协议和消息队列内核中支持 WebSocket 协议支持功能生产消费协议设计支持 WebSocket Server主动消息推送RabbitMQ / Pulsar 如何支持 WebSocket 协议总结导图

Java基础面试题精选:深入探讨哈希表、链表和接口等

目录 1.ArrayList和LinkedList有什么区别&#xff1f;&#x1f512; 2.ArrayList和Vector有什么区别&#xff1f;&#x1f512; 3.抽象类和普通类有什么区别&#xff1f;&#x1f512; 4.抽象类和接口有什么区别&#xff1f;&#x1f512; 5.HashMap和Hashtable有什么区别&…

百数服务商——顶杰云,为建筑行业数字化转型“添砖加瓦”

杭州顶杰科技有限公司&#xff1a; 顶杰科技是国内一家行业领先的软件与信息技术服务提供商同时也是百数在建筑业的垂直领域服务商&#xff0c;通过低代码、云计算、AI大数据、IOT、区块链等先进的产品和技术&#xff0c;致力服务于政府、运营商、央国企、制造、金融、教育、能…

AI项目十:Swin Transformer目标检测环境搭建

若该文为原创文章&#xff0c;转载请注明原文出处。 Swin Transformer是做什么的这里不做介绍&#xff0c;主要是记录下学习的全过程&#xff0c;Swin Transformer在搭建和训练的过程中&#xff0c;折腾了很久&#xff0c;主要是在折腾环境。 一、AutoDL租用实例 个人没有GP…

多线程的学习中篇下

volatile 关键字 volatile 能保证内存可见性 volatile 修饰的变量, 能够保证 “内存可见性” 示例代码: 运行结果: 当输入1(1是非O)的时候,但是t1这个线程并沿有结束循环, 同时可以看到,t2这个线程已经执行完了,而t1线程还在继续循环. 这个情况,就叫做内存可见性问题 ~~ 这…

初识Java 11-2 函数式编程

目录 高阶函数 闭包 函数组合 柯里化和部分求值 本笔记参考自&#xff1a; 《On Java 中文版》 高阶函数 ||| 高阶函数的定义&#xff1a;一个能接受函数作为参数或能把函数当返回值的函数。 把函数当返回值的情况&#xff1a; import java.util.function.Function;inter…

26551-2011 畜牧机械 粗饲料切碎机

声明 本文是学习GB-T 26551-2011 畜牧机械 粗饲料切碎机. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了粗饲料切碎机的产品型号、技术要求、试验方法、检验规则、标志、包装、运输与贮存。 本标准适用于加工农作物秸秆等粗饲料…

Python接口自动化之unittest单元测试

以下主要介绍unittest特性、运行流程及实际案例。 一、单元测试三连问 1、什么是单元测试&#xff1f; 按照阶段来分&#xff0c;一般就是单元测试&#xff0c;集成测试&#xff0c;系统测试&#xff0c;验收测试。单元测试是对单个模块、单个类或者单个函数进行测试。 将…

迅为龙芯2K1000开发板通过汇编控制GPIO

上一小节&#xff0c;我们使用了 C 语言控制了 gpio&#xff0c;这一小节我们来看一下如何使用汇编来控制 gpio 呢&#xff1f;有的 同学可能会有疑问了&#xff0c;既然我们可以使用 C 语言来控制 gpio&#xff0c;为什么我们还要使用更底层的汇编语言呢&#xff0c; 如果我…

【Read View】Read View如何在MVCC里面工作、事务的隔离级别如何实现等重点知识汇总

目录 Read View 在 MVCC 里如何工作的 隔离级别如何实现的呢 Read View 在 MVCC 里如何工作的 ReadView用于管理事务之间的数据一致性&#xff0c;特别是在并发访问数据库时。 那 Read View 到底是个什么东西&#xff1f; Read View 有四个重要的字段&#xff1a; m_ids &…

Python函数:chr()和ord()

两个函数是基于Unicode编码表进行进行字符与字码之间的转换。 chr()函数是通过字码转换成字符: 如图,坐标(1,4e10)丑 使用chr需要线将坐标相加得到&#xff1a;4e11 chr默认传入10进制的字码. 如图是各进制的字码。 也可以传入其他进制&#xff0c;不过需要在前面传入的参数最前…

canvas+javascript实现点击更改图片中指定部位的颜色(将近似的颜色值变更为自定义的颜色)

原图&#xff1a; 完整代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" co…

前端架构师之02_ES6_高级

1 类和继承 1.1 class类 JavaScript 语言中&#xff0c;生成实例对象的传统方法是通过构造函数。 // ES5 创建对象 // 创建一个类&#xff0c;用户名 密码 function User(name,pass){// 添加属性this.name name;this.pass pass; } // 用 原型 添加方法 User.prototype.sho…

跨境电商如何利用海外代理IP,提高竞争力?

随着经济全球化的深度发展&#xff0c;跨境电商已经成为外贸发展的主要赛道&#xff0c;跨境电商王者般的新业态&#xff0c;近年来&#xff0c;我国跨境电商发展得到政府的大力扶持。而代理IP也逐渐成为助力跨境业务的强大工具之一。可以为我们跨境电商种出现的如地域限制、安…