写在前面
- 这个专栏的内容记录的是Verilog题库刷题过程,附带RTL\TestBench,并进行
代码覆盖率收集
。- 该题库算是一个
Verilog宝藏刷题网站
了,提供在线仿真环境(题库),<刷题记录>专栏,持续打卡中…
一、题目
(1)题目描述
在数字芯片设计中,经常把实现特定功能的模块编写成函数,在需要的时候再在主模块中调用,以提高代码的复用性和提高设计的层次,分别后续的修改。
请用函数实现一个4bit数据大小端转换的功能。实现对两个不同的输入分别转换并输出。
(2)信号示意图
(4)端口描述
信号 | 方向 | 类型 | 位宽 | 描述 |
---|---|---|---|---|
clk | input | wire | 1bit | 时钟,时钟周期为5ns |
rst_n | input | wire | 1bit | 复位信号,异步下降沿有效 |
a | input | wire | 4bit | 无符号数 |
b | input | wire | 4bit | 无符号数 |
c | output | reg | 4bit | 无符号数 |
d | output | reg | 4bit | 无符号数 |
二、分析
//函数定义 function <返回值位宽或类型说明> 函数名;
端口声明;
局部变量定义;
其他语句;
endfunction
//函数调用 <函数名>(<表达式> <表达式>)
function[7:0] gefun; //函数的定义
input [7:0] x;
...
<语句> //进行运算
gefun = count; //赋值语句
endfunction
assign number = gefun(rega); //对函数的调用
//注1:函数的调用是通过将函数作为调用函数的表达式中的操作数来实现的
//注2:函数在综合时,被理解成具有独立运算功能的电路,每调用一次函数,相当于改变此电路的输入,以此得到相应的计算结果
在使用function语句时,需要注意的点如下:
- function的定义不能包含任何时间控制语句——用延迟#、事件控制@或等待wait标识的语句;
- function不能启动(即调用)任务;
- 定义function时至少要有一个输入参量!且不能有任何输出或输入/输出双向变量。
- 在function的定义中必须有一条赋值语句,给函数中的一个内部寄存器赋以函数的结果值,该内部寄存器与函数同名
三、RTL
module function_mod(
input clk,
input rst_n,
input [3:0] a,
input [3:0] b,
output reg [3:0] c,
output reg [3:0] d
);
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
c <= 4'b0;
d <= 4'b0;
end
else begin
c <= bigend_2_littleend(a);
d <= bigend_2_littleend(b);
end
end
/*-----------------------------------------------\
-- function --
\-----------------------------------------------*/
function [3:0] bigend_2_littleend;
input [3:0] data;
begin
bigend_2_littleend[3] = data[0];
bigend_2_littleend[2] = data[1];
bigend_2_littleend[1] = data[2];
bigend_2_littleend[0] = data[3];
end
endfunction
endmodule
四、Testbench
`timescale 1ps/1ps
module tb_functon_mod;
reg clk;
reg rst_n;
reg [3:0] a ;
reg [3:0] b ;
wire [3:0] c ;
wire [3:0] d ;
/*-----------------------------------------------\
-- --
\-----------------------------------------------*/
initial begin
clk = 1;
rst_n = 1;
#1000 rst_n = 0;
#4001 rst_n = 1;
repeat(10000)begin
d_case(a,b,{$random}%16,{$random}%16);
#5000 ;
end
end
/*-----------------------------------------------\
-- --
\-----------------------------------------------*/
task d_case;
output [3:0] a;
output [3:0] b;
input [3:0] a0;
input [3:0] b0;
begin
a = a0 ;
b = b0 ;
end
endtask
/*-----------------------------------------------\
-- clock period is 5ns --
\-----------------------------------------------*/
always begin
#2500 clk = ~clk;
end
/*-----------------------------------------------\
-- display --
\-----------------------------------------------*/
//-- debug signal
reg [3:0] a_buff;
reg [3:0] b_buff;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
a_buff <= 4'bz;
b_buff <= 4'bz;
end
else begin
a_buff <= a;
b_buff <= b;
end
end
always @ (c)begin
if(c == {a_buff[0],a_buff[1],a_buff[2],a_buff[3]})begin
end
else begin
$display($realtime,", error:a = %d ;c = %d;",a_buff,c);
end
end
always @ (d)begin
if(d == {b_buff[0],b_buff[1],b_buff[2],b_buff[3]})begin
end
else begin
$display($realtime,", error:b = %d ;d = %d;",b_buff,d);
end
end
function_mod u_function_mod(
.clk(clk),
.rst_n(rst_n),
.a (a ),
.b (b ),
.c (c ),
.d (d )
);
initial #60000000 $finish;
initial begin
$fsdbDumpfile("function_mod.fsdb");
$fsdbDumpvars ;
$fsdbDumpMDA ;
end
endmodule
五、结果分析
(1)TB结果
在display部分,输出数据直接与输入数据的大小端变化后的值直接比较,输出无误。该错误是由于该时刻,a和b还没开始更新而导致。恰巧验证该部分程序的正确性。
(2)波形图
可以看到,在复位后的时钟上升沿来临之后,开始采集数据并进行转换,可以对比出输出数据由输入数据的大小端转换而来。
(3)覆盖率
代码覆盖率100%
✍✍☛ 题库入口
经过一段时间的沉淀,发现入行IC行业,自己的底子还是很差,写的文章质量参差不齐,也没能解答大家的疑问。决定还是要实打实从基础学起,由浅入深。因此决定通过补充/完善基础知识的同时,通过题库刷题不断提高自己的设计水平,题库推荐给大家(点击直达),<题库记录>栏目不定期更新,欢迎前来讨论。
作者:xlinxdu
版权:本文版权归作者所有
转载:未经作者允许,禁止转载,转载必须保留此段声明,必须在文章中给出原文连接。