#!/user/bin/perl -w
use strict;
use POSIX;
my $cur_time = strftime("%m/%d/%Y",localtime());
my $file_name;
my $outfile_name;
my $module_name;
my $tb_module_name;
my $author_name = "Sniper";
my $tab = " "x4;
my @input;
my @output;
my @signal;
my @parameter;
$file_name = $ARGV[0] if(@ARGV == 1);
&help_message() if(@ARGV != 1);
open(LOG,"<",$file_name) or die "Can not open $file_name for reading!\n";
while (defined(my $line = ))
{
chomp $line;
next if ($line =~ /\A\s*\z/);
$line =~ s/\A\s*|\s*\z//g;
#module name
if($line =~ /\Amodule\s*([a-zA-Z0-9_]+)/)
{
$module_name = $1;
$tb_module_name = "tb_" . $module_name;
}
#parameter
if($line =~ /parameter\s*([a-zA-Z0-9_]+)\s*=\s*(\d+)/)
{
push (@parameter, "parameter $1 = $2");
}
#io port
if($line =~ /\Ainput\s*([a-zA-Z0-9_]+)/)
{
push (@input, "input $1");
push (@signal, "input $1");
}
elsif($line =~ /\Ainput\s*\[([a-zA-Z0-9_-]+):(\d+)\]\s*([a-zA-Z0-9_]+)/)
{
push (@input, "input [$1:$2] $3");
push (@signal, "input [$1:$2] $3");
}
elsif($line =~ /\Aoutput\s*reg\s*([a-zA-Z0-9_]+)/)
{
push (@output, "output $1");
push (@signal, "output $1");
}
elsif($line =~ /\Aoutput\s*reg\s*\[([a-zA-Z0-9_-]+):(\d+)\]\s*([a-zA-Z0-9_]+)/)
{
push (@output, "output [$1:$2] $3");
push (@signal, "output [$1:$2] $3");
}
elsif($line =~ /\Aoutput\s*([a-zA-Z0-9_]+)/)
{
push (@output, "output $1");
push (@signal, "output $1");
}
elsif($line =~ /\Aoutput\s*\[([a-zA-Z0-9_-]+):(\d+)\]\s*([a-zA-Z0-9_]+)/)
{
push (@output, "output [$1:$2] $3");
push (@signal, "output [$1:$2] $3");
}
}
close (LOG);
print "DUT module name: " . $module_name . "\n";
foreach (@parameter) {print $_ . "\n";}
foreach (@input) {print $_ . "\n";}
foreach (@output) {print $_ . "\n";}
my $str = "";
$str .= "`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: $cur_time
// Author Name: $author_name
// Module Name: $tb_module_name
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////";
$str .= "
module $tb_module_name;
";
if (defined($parameter[0]))
{
$str .= "//parameter\n";
foreach (0..$#parameter)
{
my $change = $parameter[$_];
$str .= $change . ";\n";
}
$str .= "\n\n";
}
$str .= "//input\n";
foreach (@input)
{
my $change = $_;
$change =~ s/\Ainput/reg/;
$str .= $change .";\n";
}
$str .= "\n\n";
$str .= "//output\n";
foreach (@output)
{
my $change = $_;
$change =~ s/\Aoutput/wire/;
$str .= $change . ";\n";
}
$str .= "
initial
begin
";
foreach (@input)
{
my $change = $_;
if($change =~ /\Ainput\s*([a-zA-Z0-9_]+)/)
{
$change = "${tab}$1 = 0;\n";
}
elsif($change =~ /\Ainput\s*\[([a-zA-Z0-9_-]+):(\d+)\]\s*([a-zA-Z0-9_]+)/)
{
$change = "${tab}". $3 ."[". $1 .":". $2 ."] = 0;\n";
}
$str .= $change;
}
$str .= "
#100;
end
//clock
//always #5 clk = ~clk;
//DUT
$module_name ";
if (defined($parameter[0]))
{
$str .= "\n#(\n";
foreach (0..$#parameter)
{
my $change = $parameter[$_];
if($change =~ /\s+([a-zA-Z0-9_]+)\s*=/)
{
$change = "${tab}.$1($1),\n" if ($_ != $#parameter);
$change = "${tab}.$1($1)\n" if ($_ == $#parameter);
}
$str .= $change;
}
$str .= ")\n";
}
$str .= "DUT\n(\n";
foreach (0..$#signal)
{
my $change = $signal[$_];
if($change =~ /\s+([a-zA-Z0-9_]+)\z/)
{
$change = "${tab}.$1($1),\n" if ($_ != $#signal);
$change = "${tab}.$1($1)\n" if ($_ == $#signal);
}
$str .= $change;
}
$str .=");
initial
begin
\$dumpfile(\"curve.vcd\");
\$dumpvars(0,DUT);
end
endmodule
";
$outfile_name = $tb_module_name . ".v";
open(OUT,">",$outfile_name) or die "Can not open $outfile_name for writting!\n";
print OUT $str;
close (OUT);
print "\nThe file $outfile_name has been generated!\n\n";
sub help_message
{
print "\n\n" . "-"x60 . "\n";
print "THe $0 script used to generate a module testbench.\n\n";
print "Usage: perl $0 module_file_name\n\n";
print "Example: perl $0 top.v\n";
print "-"x60 . "\n\n";
exit;
}
perl generate_testbench file_name.v
待处理的module:
module AsyncFIFO
#(
parameter DATA_WIDTH = 8,
parameter DATA_DEPTH = 256,
parameter ADDR_WIDTH = 8
)
(
input FIFO_rst_n,
input Write_clk,
input Write_enable,
input [DATA_WIDTH-1:0] Write_data,
input Read_clk,
input Read_enable,
output reg Read_valid,
output reg [DATA_WIDTH-1:0] Read_data,
output Empty_flag,
output Full_flag
);
处理结果:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 08/12/2020
// Author Name: Sniper
// Module Name: tb_AsyncFIFO
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module tb_AsyncFIFO;
//parameter
parameter DATA_WIDTH = 8;
parameter DATA_DEPTH = 256;
parameter ADDR_WIDTH = 8;
//input
reg FIFO_rst_n;
reg Write_clk;
reg Write_enable;
reg [DATA_WIDTH-1:0] Write_data;
reg Read_clk;
reg Read_enable;
//output
wire Read_valid;
wire [DATA_WIDTH-1:0] Read_data;
wire Empty_flag;
wire Full_flag;
initial
begin
FIFO_rst_n = 0;
Write_clk = 0;
Write_enable = 0;
Write_data[DATA_WIDTH-1:0] = 0;
Read_clk = 0;
Read_enable = 0;
#100;
end
//clock
//always #5 clk = ~clk;
//DUT
AsyncFIFO
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_DEPTH(DATA_DEPTH),
.ADDR_WIDTH(ADDR_WIDTH)
)
DUT
(
.FIFO_rst_n(FIFO_rst_n),
.Write_clk(Write_clk),
.Write_enable(Write_enable),
.Write_data(Write_data),
.Read_clk(Read_clk),
.Read_enable(Read_enable),
.Read_valid(Read_valid),
.Read_data(Read_data),
.Empty_flag(Empty_flag),
.Full_flag(Full_flag)
);
initial
begin
$dumpfile("curve.vcd");
$dumpvars(0,DUT);
end
endmodule
待处理的module:
module pulse_synchronizer(
input clk0,
input clk1,
input rst_n,
input select,
output DFF0_in,
output DFF1_in,
output reg [2:0] DFF0_out,
output reg [2:0] DFF1_out,
output clk_out0,
output clk_out1,
output clk_out
);
处理结果:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 08/12/2020
// Author Name: Sniper
// Module Name: tb_pulse_synchronizer
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module tb_pulse_synchronizer;
//input
reg clk0;
reg clk1;
reg rst_n;
reg select;
//output
wire DFF0_in;
wire DFF1_in;
wire [2:0] DFF0_out;
wire [2:0] DFF1_out;
wire clk_out0;
wire clk_out1;
wire clk_out;
initial
begin
clk0 = 0;
clk1 = 0;
rst_n = 0;
select = 0;
#100;
end
//clock
//always #5 clk = ~clk;
//DUT
pulse_synchronizer DUT
(
.clk0(clk0),
.clk1(clk1),
.rst_n(rst_n),
.select(select),
.DFF0_in(DFF0_in),
.DFF1_in(DFF1_in),
.DFF0_out(DFF0_out),
.DFF1_out(DFF1_out),
.clk_out0(clk_out0),
.clk_out1(clk_out1),
.clk_out(clk_out)
);
initial
begin
$dumpfile("curve.vcd");
$dumpvars(0,DUT);
end
endmodule