都是为了模块化、结构化设计,主要还是将重复性的功能封装起来方便调用。
可以对返回值类型和范围不进行定义,默认值为reg型并且位宽为1
变量类型说明 比如integer i
function(其功能同之前的module模块类似)
通常是用来描述组合逻辑,是阻塞赋值“="
不能包含任何延迟,函数仿真时间为0
只含有input参数并由函数名返回一个结果(函数名就是返回值)
可以调用其他的函数(function),不可调用task
task
通常用于调试,对硬件行为级描述,不可综合。
可以包含时序控制(#延迟、wait)
可以有input、output、inout参数
可以调用其他任务或函数,优先级较高
function和task的区别:
(1)任务能调用任务和函数,但是函数只能调用函数,不能调用任务;
(2)任务可以描述组合逻辑和时序逻辑,可以有时延;函数只能描述组合逻辑,仿真时延为0;
(3)任务可以有任意多个各种类型的输入;函数只能有input端口的输入参数,且至少输入一个参数;
(4)任务可以没有返回值;函数必须有一个返回值;
本题的testbench有问题,没有考虑clk和rst_n。所以这里则根据题意写了一份答案。
首先是module部分。因为多次采用大小位转换功能,所以直接将这部分定义为一个function,可以考虑用之前的for循环进行编写。可以缩短一部分。随后是对function的调用,考虑为时钟上升沿触发,并且异步复位。
//方法1function [3:0] swap;input [3:0] swap_num;integer i;beginfor(i = 0;i < 4;i = i + 1)beginswap[i] = swap_num[3-i];endend
endfunctionreg [3:0] c_tmp,d_tmp; //定义了两个寄存器 方便在always模块里去赋值
always @(posedge clk or negedge rst_n)if(!rst_n) beginc_tmp <= 4'b0;d_tmp <= 4'b0;endelse beginc_tmp <= swap(a);d_tmp <= swap(b);end
//方法2`timescale 1ns/1ns
module function_mod(input clk,input rst_n,input [3:0]a,input [3:0]b,output [3:0]c,output [3:0]d
);function [3:0] begin_end;input [3:0] data_in;beginbegin_end[0] = data_in[3];begin_end[1] = data_in[2];begin_end[2] = data_in[1];begin_end[3] = data_in[0];end endfunctionassign c = begin_end(a);assign d = begin_end(b);endmodule
`timescale 1ns/1ns
module tb_function();reg [3:0] a,b;reg clk;reg rst_n;wire [3:0] c,d;
always #5 clk = !clk;
initial beginclk = 0;rst_n = 0;a = 4'b0000;b = 4'b0000;#5 clk = !clk;#10 rst_n = 1; a = 4'b0001;b = 4'b0101; #30 rst_n = 1; a = 4'b1101;b = 4'b1011; #100$finish;
endfunction_mod dut(.a (a),.b (b),.clk (clk),.rst_n (rst_n),.c (c),.d (d)
);endmodule