zoukankan      html  css  js  c++  java
  • (原创)task和function语法的使用讨论(Verilog,CPLD/FPGA)

    1. Abstract

      function和task语句的功能有很多的相似之处,在需要有多个相同的电路生成时,可以考虑使用它们来实现。因为个人使用它们比较少,所以对它们没有进行更深的了解,现在时间比较充裕,我想通过写几个简单的电路将它们二者的功能进行验证一下,看看究竟是怎么生成电路的。

    2. Contents

        主要为测试function和task各自生成的电路,所以电路设计功能比较简单——4位BCD码转换成4位余3码。

        文件开头的注释说明。

    /* --------------------------------------- 
        Module Name:         temp 
        Module Function:    将4位BCD码转换成为余3码,无效状态为4'b0000 
        Module Input:         4-bit data_in 
        Module Output:      4-bit data_out 
        Module Reference:    None 
        Note:                  码表如下 
    ######################################## 
              data_in        data_out    
        0      4'b0000        4'b0011 
        1      4'b0001        4'b0100    
        2      4'b0010        4'b0101    
        3      4'b0011        4'b0110 
        4      4'b0100        4'b0111 
        5      4'b0101        4'b1000 
        6      4'b0110        4'b1001 
        7      4'b0111        4'b1010 
        8      4'b1000        4'b1011 
        9      4'b1001        4'b1100 
        10      4'b1010        4'b0000        无效 
        11      4'b1011        4'b0000        无效 
        12      4'b1100        4'b0000        无效 
        13      4'b1101        4'b0000        无效 
        14      4'b1110        4'b0000        无效 
        15      4'b1111        4'b0000        无效 
       ---------------------------------------*/

        2.1 直接使用组合逻辑电路生成BCD码转余3码。

    module temp(data_in,data_out); 
    
    output reg [3:0] data_out; 
    input [3:0] data_in; 
    
    always @(data_in) 
    begin 
        if(data_in >=  4'd10) data_out = 4'b0000; 
        else  data_out = data_in + 4'd3; 
    end 
    
    endmodule

        用RTL视图查看一下生成出来的网表

    imageFIG2.1 直接用组合逻辑生成的逻辑图

        生成出来的电路由加法器、比较器和选择器构成,输入数据data_in + 3作为选择器的选择控制,下面做一下验证测试。

    image FIG2.2 测试仿真验证

        2.2 用task语句编写组合电路

    module temp(data_in,data_out); 
    
    output reg [3:0] data_out; 
    input [3:0] data_in; 
    
    always @(data_in) 
    begin 
        if(data_in >=  4'd10) data_out = 4'b0000; 
        else  BCD2Access3(data_out,data_in); 
    end 
    
    task BCD2Access3; 
    output [3:0] data_out; 
    input [3:0] data_in; 
    
        data_out = data_in + 4'd3; 
    endtask 
    endmodule

         用RTL视图查看一下最后生成的网表。

    imageFIG2.3 使用task语句生成出的逻辑图

        仔细对比,FIG2.3和FIG2.1是一模一样的,也就是说采用task语句可以生成预期的逻辑图,非常成功!既然生成出的逻辑图都是一样的,测试部分在此就省略了吧,和FIG2.2应该是一样的。

    2.3 用function语句编写组合逻辑

    module temp(data_in,data_out); 
    
    output reg [3:0] data_out; 
    input [3:0] data_in; 
    
    always @(data_in) 
    begin 
        if(data_in >=  4'd10) data_out = 4'b0000; 
        else  data_out = BCD2Access3(data_in); 
    end 
    
    function [3:0] BCD2Access3; 
    input [3:0] data_in; 
    
    BCD2Access3 = data_in + 4'd3; 
    endfunction 
    endmodule

        用RTL视图查看一下最后生成出来的网表。

    image FIG2.4 使用function语句生成出的逻辑图

        相信已经很熟悉这个逻辑图了,与前面的FIG2.1一模一样,也就是说使用function语句也是可以生成预期的电路的,而且也是非常成功的!既然逻辑图都是与前面一致的,故测试部分……也省去了吧。

       小结一下,用function和task语句都可以生成预期的逻辑电路,不过,查查语法书,可以知道task语句的适用性更广泛一点,更符合逻辑思维的习惯;function最大的好处就是可以有一个返回值,运算以后结果可以直接返回供调用的块使用。

      在组合逻辑设计的过程中,写成可综合的电路可以达到预期的生成电路逻辑,那么在时序逻辑设计中,function和task语句又会生成出怎样的电路呢?还是以这一个电路功能为模板,值得注意的是,得额外加一个时钟信号。

    2.4 直接使用时序逻辑编写的BCD码转余3码。

    module temp(data_in,data_out,clk); 
    
    output reg [3:0] data_out; 
    input [3:0] data_in; 
    input clk; 
    
    always @(posedge clk) 
    begin 
        if(data_in >=  4'd10) data_out = 4'b0000; 
        else  data_out <= data_in + 3'd3; 
    end 
    
    endmodule

        用RTL视图来看下生成出来的逻辑网表。

    imageFIG2.5 直接用时序逻辑编写生成的逻辑网表

        和上面生成的逻辑网表相比,多了一个锁存器,这也是典型的时序逻辑的特征,数据的变化只在clk的上升沿才有效。下面来做一下电路逻辑的验证。

    image FIG2.6 时序逻辑网表的验证

        图确实有点小,可能看起来有点不方便,但逻辑的功能是正确的,每到clk的上升沿,数据更新一次,译码是正确的,为了方便看,再截取一部分出来吧,作为一个局部放大图。

    image FIG2.7 时序逻辑验证的局部放大图

        直接用时序逻辑设计成功了,再尝试着用task语句和function语句实现,看看最后的效果会怎么样。

    2.5 时序逻辑下使用task语句实现电路

    module temp(data_in,data_out,clk); 
    
    output reg [3:0] data_out; 
    input [3:0] data_in; 
    input clk; 
    
    always @(posedge clk) 
    begin 
        if(data_in >=  4'd10) data_out = 4'b0000; 
        else  BCD2Access3(data_out,data_in); 
    end 
    
    task BCD2Access3; 
    output [3:0] data_out; 
    input [3:0] data_in; 
    
        data_out = data_in + 4'd3; 
    endtask 
    
    endmodule

        用RTL视图来看一下生成的逻辑网表。

    imageFIG2.8 使用task语句生成的逻辑网表

         同样,仔细对照一下,发现FIG2.8和FIG2.6是一样的,也就是说在时序逻辑中使用task语句也是可以实现预期的电路的,非常的成功!和上述讨论的一样,既然逻辑图相同的话,验证的部分就略去了吧。

    2.6 时序逻辑下用function语句实现电路

    module temp(data_in,data_out,clk); 
    
    output reg [3:0] data_out; 
    input [3:0] data_in; 
    input clk; 
    
    always @(posedge clk) 
    begin 
        if(data_in >=  4'd10) data_out = 4'b0000; 
        else  data_out <= BCD2Access3(data_in); 
    end 
    
    function [3:0] BCD2Access3; 
    input [3:0] data_in; 
    
    BCD2Access3 = data_in + 4'd3; 
    endfunction 
    
    endmodule

        跟上面一样,用RTL视图来看看最后生成出来的电路。

    image FIG2.9 时序逻辑下使用function语句生成的逻辑网表

        仔细对比,会发现跟如上的逻辑网表一样,也就是说在时序逻辑下使用function语句也是可以实现预期的电路的,非常的成功!逻辑网表一致的话,在此逻辑的验证容我略去吧。

        小结一下,在时序逻辑的电路设计中,也可以使用task语句和function语句来实现电路。

        在学习过程中,也不断的在看语法书,毕竟这一块是我不太熟悉的地方,现在将它们使用的一些要点整理出来,对如何使用和最后生成怎样的很有参考帮助。

    task语句要点 

    (1)若用于任务中的命名变量或参数没有在任务块中声明,则指的是在模块中声明的命名变量或参数。

    (2)任务中的input,output和inout的个数不受限制(也可以为0个)。(任务可以没有参数)

    (3)任务中的变量(包括输入(input)和双向端口(inout))可以声明为寄存器型。如果没有明确地声明,则默认为寄存器类型,且其位宽与相应的变量匹配。

    (4)当启动任务时,相应于任务的输入和双向端口(inout)的变量表达式的值被存入相应的变量寄存器中。当任务结束时,输入和双向端口(inout)的变量寄存器中的值又被代入启动任务的语句中相应的表达式。

    电路综合参考:包含时序控制语句的任务是不可综合的。启动的任务往往被综合成组合逻辑。 

    function语句要点

    (1)函数必须至少有一个输入变量,不能有任何输出或输入/输出双向变量(output 和inout类型)。

    (2)函数不能包含时间控制语句(如延迟#、事件控制@或者等待wait)。

    (3)函数是通过对函数名赋值的途径返回其值的,就好比是一个寄存器。

    (4)函数不能启动任务。

    (5)函数不能被禁用。(特指应用于编写测试文件)

        电路综合参考:函数的每一次调用都被综合为一个独立的组合逻辑电路块。

    3.Conclusion

        总体来说,task的功能更加符合硬件逻辑设计的习惯,而且语法中对它的限制比较少。而且它们最终生成的电路都是组合逻辑,所以在需要产生多个相同的模块时,可以采用由它们构成。

    4.Platform

      Quartus II 9.1 Build 222 Full Version

    5.Reference

    [1] Verilog 数字系统设计教程(第2版) 夏宇闻

    [2] Advanced Digital Design with the Verilog HDL (Second Edition) Michael D.Ciletti

  • 相关阅读:
    JavaScript实现类的private、protected、public、static以及继承
    OSS网页上传和断点续传(STSToken篇)
    OSS网页上传和断点续传(OSS配置篇)
    Linq sum()时遇到NULL
    SQLSERVER事务日志已满 the transaction log for database 'xx' is full
    笔记本高分辨软件兼容问题,字体太小或模糊
    H5上传图片之canvas
    An error occurred while updating the entries. See the inner exception for details.
    无限级结构SQL查询所有的下级和所有的上级
    SQLserver 进程被死锁问题解决
  • 原文地址:https://www.cnblogs.com/hechengfei/p/4104253.html
Copyright © 2011-2022 走看看