day10-verilog---模块的调用,任务和函数

模块的调用(上层模块对底层模块的调用)

  • 在做模块划分时,通常会出现这种情形,某个大的模块中包含了一个或多个功能子模块,verilog是通过模块调用或称为模块实例化的方式来实现这些子模块与高层模块的连接的

  • 调用模块实例化的一般形式为:

  • <模块名><参数列表><实例名>(<端口列表>);

  • 其中参数列表是传递到子模块的参数值,参数传递的典型应用是定义门级时延。

  • 信号端口可以通过位置或名称关联,但是关联方式不能够混合使用

名称关联&位置关联

  • 定义模块:module Design(端口1,端口2,端口3...)

  • 位置关联:

  • 引用时,严格按照模块定义的端口顺序来连接,不用标明元模型定义时规定的端口名。

Design u1(u1的端口1,u1的端口2,u1的端口3)
  • 名称关联:

  • 引用时用“.”符号,标明原模型定义时规定的端口名:

Design u2(.端口1(u1的端口1),
.端口2(u1的端口2),
.端口3(u1的端口3)
)

eg:

module and(C,A,B)
input A,B;
output C;
位置相关
and A1 (T3,A,B)
名称相关
and A2(
    .C(T3),
    .A(A),
    .B(B)
)

(1条消息) 关于verilog实例化的介绍_能饮一杯吴?的博客-CSDN博客_verilog实例化

模块的调用---参数传递

//子模块
module Decode(A,F);
    parameter width =1,polarity=1;
endmodule
//顶层模块
moudle top;
    wire [3:0] A4;
    wire [4:0] A5;
    wire [15:0] F16;
    wire [31:0] F32;
    Decode #(4,0) D1(A4,F16);
endmodule

ps:在top模块中引用Decode实例时,可通过参数的传递来改变定义时已规定的参数值,即通过

#(4,0),实例D1实际引用的是参数width和polarity分别为4与0时的Decode模块

传递参数的另一种方法

module_name #(.parameter name(para_value),.parameter name(para_value)) inst_name(port_map)
实际就为:
Decode #(.width(4),.polarity(0)) D1(A4,F16)

注意事项

  • 位选择,如.C(D[0]),C端口接到了D信号的第0bit位;

  • 部分选择,如.Bus(Din[5:4])

  • 上述类型的合并,如.Addr({A1,A2[1:0]})

悬空端口的处理:

在实例化中,可能有些管脚没用到,可在映射中留白处理

DFF d1(
.Q(QS),
.Qbar(),
.Data(D),
.Preset(),//该管脚悬空
.clock(CK);
)

PS:输入管脚悬空,该管脚输入为高阻Z,输出管脚悬空,该管脚废弃不用

任务和函数

  • task和function语句分别用来由用户定义任务和函数;

  • 任务和函数往往时大的程序模块中在不同地点多次用到的相同的程序段

  • 利用任务和函数可将一个很大的程序模块分解为许多较小的任务和函数,便于理解和调试

任务定义

task<任务名>;
    端口及数据类型声明语句;
    其他语句;
endtask

任务调用

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

task语句

  • 任务的定义与调用必须在一个module模块内

  • 任务被调用时,需列出端口名列表,且必须与任务定义中的I/0变量一一对应

  • 一个任务可以调用其他任务和函数

//任务定义
task my_task;
    input a,b;
    inout c;//一个三态门,由一个开关控制这个门是输入还是输出
    output d,e;
    ......
    <语句>//执行任务工作相应的语句
    .....
    c = foo1;
    d = foo2;
    e = foo3;//对任务变量进行赋值
endtask

//任务调用
my_task(v,w,x,y,z)//为位置关联,v对应a,w对应b,c对应x,y对应d,z对应e
day10-verilog---模块的调用,任务和函数_第1张图片

函数function(可以综合)

  • 函数的目的是通过返回一个用于某表达式的值,来响应输入信号(适于对不同变量采取同一运算的操作)

  • 函数在模块内部定义,通常在本模块中调用,也能根据按模块层次分级命名的函数名从其他模块调用。而任务只能在同一模块内定义与调用

function<返回值位宽或类型说明>函数名;//如缺少位宽定义,则默认为一
 端口声明;
 局部变量定义;
 其他语句;
endfunction

函数的调用 <函数名>(<表达式><表达式>)

注:函数的调用是通过将函数作为调用函数的表达式中的操作数来实现的

函数规则
  • 函数不能包含任何时间控制的语句,如#,@,wait,poesdge,negedege

  • 函数不能调用任务,因为任务可以包含时间控制语句,但是可以调用其他函数

  • 函数应该至少有一个输入

  • 函数不能有非阻塞性的赋值或force....release或assign...deassign

  • 函数不能有任何触发器

  • 函数不能有output或inout

函数的声明:

function [7:0] sum;
    input [7:0] a, b;
    begin
        sum = a + b;
    end
endfunction

function [7:0] sum (input [7:0] a, b);
    begin
        sum = a + b;
    end
endfunction
————————————————
版权声明:本文为CSDN博主「李锐博恩」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Reborn_Lee/article/details/107447734

函数的调用:

reg [7:0] result;
reg [7:0] a, b;

initial begin
    a = 4;
    b = 5;
    #10 result = sum (a, b);
end

利用一个函数对一个8位二进制数中为0的位进行计数

//count the numbers of 0 in rega[7:0]
module count_0 (numbers,rega);
    output [7:0] numbers;
    input [7:0] rega;
    function [7:0] get_n_of_0; //define a function
        input [7:0] x;
        reg [7:0] count;
        integer i;
            begin
                count = 0;
                for(i=0;i<=7;i++)
                    if(x[i] == 1'b0) 
                        count = count +1;
                    get_n_of_0 = count; //函数名就相当于输出变量;
                end;
    endfunction
assign number = get_n_of_0(rega);
endmodule

ps:函数名就相当于输出变量

函数和任务的区别

任务task

函数function

目的或用途

可计算多个结果值

通过返回一个值,来响应输入信号

function的名字即可作为参数,作输出

输入与输出

可为各种类型(包括input型)

至少有一个输入变量,但不能有任何output或input型变量

被调用

只可在过程赋值语句中调用(过程赋值语句为阻塞赋值和非阻塞赋值),不能在连续赋值语句中调用(连续赋值的关键词为assign)

可作为表达式中的一个操作数来调用,在过程赋值和连续赋值语句中均可调用

调用其他任务和函数

任务可调用其他任务和函数

函数可调用其他函数,但不可调用其他任务

返回值

不向表达式返回值

像调用它的表达式返回一个值

day10-verilog---模块的调用,任务和函数_第2张图片

你可能感兴趣的:(芯片验证,fpga开发,单片机,嵌入式硬件)