一、function和task
都是为了模块化、结构化设计,主要还是将重复性的功能封装起来方便调用。
可以对返回值类型和范围不进行定义,默认值为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的调用,考虑为时钟上升沿触发,并且异步复位。
三、设计文件
//方法1
function [3:0] swap;
input [3:0] swap_num;
integer i;
begin
for(i = 0;i < 4;i = i + 1)
begin
swap[i] = swap_num[3-i];
end
end
endfunction
reg [3:0] c_tmp,d_tmp; //定义了两个寄存器 方便在always模块里去赋值
always @(posedge clk or negedge rst_n)
if(!rst_n) begin
c_tmp <= 4'b0;
d_tmp <= 4'b0;
end
else begin
c_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;
begin
begin_end[0] = data_in[3];
begin_end[1] = data_in[2];
begin_end[2] = data_in[1];
begin_end[3] = data_in[0];
end
endfunction
assign 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 begin
clk = 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;
end
function_mod dut(
.a (a),
.b (b),
.clk (clk),
.rst_n (rst_n),
.c (c),
.d (d)
);
endmodule