最近在看vivado的官方例程,顺便总结一下比较常用且优雅的testbench代码。将这些代码封装一下,以后在仿真时直接调用,非常的方便。
产生单端时钟(tb_clockgen_single .v)
//-----------------------------------------------------------------------------
//
// Copyright (c) JoeJoe.
//
// Project : Common Testbench
// Module : tb_clockgen_single .v
// Parent :
// Children : none
//
// Description:
// This is a general single clock generation module. It should be instantiated
// and connected to both the DUT
//
//
// Parameters:
// None
//
// Notes :
//
// Multicycle and False Paths
// None - this is a testbench file only, and is not intended for synthesis
//
`timescale 1ns/1ps
module tb_clockgen_single #
(
parameter PERIOD = 500 // 周期
)
(
output reg clk
);
//***************************************************************************
// Parameter definitions
//***************************************************************************
//***************************************************************************
// Register declarations
//***************************************************************************
//***************************************************************************
// Code
//***************************************************************************
initial begin
clk = 0;
forever begin
#(PERIOD/2.0)
clk = ~clk;
end // forever
end // initial
endmodule
非常常见的时钟激励编写方式。时钟通过clk端口输出,周期通过参数传入。
产生差分时钟(tb_clockgen_diff.v)
//-----------------------------------------------------------------------------
//
// Copyright (c) JoeJoe.
//
// Project : Common Testbench
// Module : tb_clockgen_diff.v
// Parent :
// Children : none
//
// Description:
// This is a general differential clock generation module. It should be instantiated
// and connected to both the DUT
//
//
// Parameters:
// None
//
// Notes :
//
// Multicycle and False Paths
// None - this is a testbench file only, and is not intended for synthesis
//
`timescale 1ns/1ps
module tb_clockgen_diff #
(
parameter PERIOD = 500 // 周期
)
(
output reg clk_p
,output reg clk_n
);
//***************************************************************************
// Parameter definitions
//***************************************************************************
//***************************************************************************
// Register declarations
//***************************************************************************
//***************************************************************************
// Code
//***************************************************************************
// Generate the clock
initial begin
clk_p = 0;
clk_n = ~clk_p;
forever begin
#(PERIOD/2.0)
clk_p = ~clk_p;
clk_n = ~clk_p;
end // forever
end // initial
endmodule
和前一个没什么区别,只是用于产生差分时钟。时钟通过clk_p,clk_n端口输出,周期通过参数传入。
产生复位信号(tb_reset.v)
//-----------------------------------------------------------------------------
//
// Copyright (c) JoeJoe.
//
// Project : Common Testbench
// Module : tb_reset.v
// Parent :
// Children : none
//
// Description:
// This is a general reset generation module. It should be instantiated
// and connected to both the DUT
//
//
// Parameters:
// None
//
// Notes :
//
// Multicycle and False Paths
// None - this is a testbench file only, and is not intended for synthesis
//
`timescale 1ns/1ps
module tb_resetgen #
(
parameter RESET_POL = 1 // 0: 复位低电平有效; 1: 复位高电平有效
)
(
input clk
,output reg reset
);
//***************************************************************************
// Parameter definitions
//***************************************************************************
//***************************************************************************
// Register declarations
//***************************************************************************
//***************************************************************************
// Code
//***************************************************************************
initial begin
reset = RESET_POL;
end // initial
task assert_reset (
input [31:0] num_clk
);
begin
$display("%t Asserting reset for %d clocks",$realtime, num_clk);
reset = RESET_POL;
repeat (num_clk) @(posedge clk);
$display("%t Deasserting reset",$realtime);
reset = ~RESET_POL;
end
endtask
endmodule
复位极性可通过参数配置,复位时长可配置。
顶层文件(tb_test.v)
`timescale 1ns / 1ps
//
// Company:
// Engineer: JoeJoe
//
// Create Date: 2024/05/13 21:49:42
// Design Name:
// Module Name: tb_test
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module tb_test();
//***************************************************************************
// Parameter definitions
//***************************************************************************
parameter SYS_PERIOD = 10; // 10ns
parameter APB_PERIOD = 10; // 10ns
//***************************************************************************
// Register declarations
//***************************************************************************
wire sys_clk_p;
wire sys_clk_n;
wire apb_clk;
wire sys_rst;
wire apb_rstn;
//***************************************************************************
// Tasks
//***************************************************************************
task init(
);
begin
fork
// Assert the reset for 40 clocks
U0_TB_RESETGEN.assert_reset(40);
U1_TB_RESETGEN.assert_reset(40);
join
#100_000; // Wait for clocks to stabilize
end
endtask
//***************************************************************************
// Code
//***************************************************************************
tb_clockgen_diff # (
.PERIOD ( SYS_PERIOD )
)
U_TB_CLOCKGEN_DIFF (
.clk_p ( sys_clk_p )
,.clk_n ( sys_clk_n )
);
tb_clockgen_single # (
.PERIOD ( APB_PERIOD )
)
U_TB_CLOCKGEN_SINGLE (
.clk ( apb_clk )
);
tb_resetgen # (
.RESET_POL ( 1'b0 )
)
U0_TB_RESETGEN (
.clk ( apb_clk )
,.reset ( apb_rstn )
);
tb_resetgen # (
.RESET_POL ( 1'b1 )
)
U1_TB_RESETGEN (
.clk ( sys_clk_p )
,.reset ( sys_rst )
);
initial begin
$timeformat(-9,2," ns",14);
#10;
$display("%t Starting simulation",$realtime);
init();
$stop;
$finish;
end
endmodule
这里的顶层文件即是一个非常nice的testbench模板,每次在仿真时可以直接搬去用,非常优雅。