Testbench::Regression

本文全面概述了信息技术领域的多个细分技术领域,包括前端开发、后端开发、移动开发、游戏开发、大数据开发等,并深入探讨了各类技术的核心概念、发展趋势及应用实例。
 

package Testbench::Regression;
require 5.000;
require Exporter;

use strict;
use vars qw ($Debug $VERSION $info $error $debug);
use Carp;
use IO::File;
use File::Find;
use Pod::Find qw(pod_where);
use Pod::Usage;

###############################################
#### Configuration Section 
$Debug = 0;
$VERSION = '1.1';

### message
$info  = "###(info) $0";
$error = "###(error) $0";
$debug = "###(debug) $0";

###############################################
###############################################
###############################################
sub new {
    @_>=1 or croak 'usage: Testbench::Regression->new({options})';
    my $class = shift;
    $class ||= "Testbench::Regression";
    my $self = {
        bfm => 'cpm',
        bfmdir => 'arm',
        tests => [],
        lefts => [],
        filter => [],
        filterout => [],
        message => [],
        nomessage => [],
        __tmp  => [],
        @_
    };
    bless $self, $class;
    return $self;
}

###############################################
## display class member for debugging
sub display {
    my $self=shift;
    print "bfm => $self->{bfm}\n";
    print "bfmdir => $self->{bfmdir}\n";
    $self->_print_refarray("tests");
    $self->_print_refarray("lefts");
    $self->_print_refarray("filter");
    $self->_print_refarray("filterout");
    $self->_print_refarray("message");
    $self->_print_refarray("nomessage");
}

## display usage and exit
sub usage {
    my $self=shift;
    my $v=shift;
    pod2usage( -input => pod_where({-inc=>1},__PACKAGE__), -verbose=>$v, -exitval=>1);
}

## Get all tests which meet requirement
sub gettests {
    my $self = shift;
    ## closure to support arguments
    find(sub{_process($self);},"../$self->{bfm}_tests");
    $self->_log_check();
    return @{$self->{tests}};
}

sub _process {
    my $self = shift;
    my $select = 1;
    my $reject = 0;
    ## only process directory
    if (-d) {
        if (/CVS/) {
            $File::Find::prune=1;
        }
        elsif (-d "$_/$self->{bfmdir}") {
            $File::Find::prune=1;
            # filter
            $select = _filter($self->{filter},$_,1);
            $reject = _filterout($self->{filterout},$_,1);
            $select |= _filter($self->{filter},$File::Find::name,0);
            $reject |= _filterout($self->{filterout},$File::Find::name,0);
            if (!$select || $reject) {
                push @{$self->{lefts}}, $File::Find::name;
                print "$debug: filtered out -- $File::Find::name\n" if $Debug;
            }
            else {
                push @{$self->{__tmp}}, $File::Find::name;
                print "$debug: matches -- $File::Find::name\n" if $Debug;
            }
            $select=1;
            $reject=0;
        }
    }
}

## check simulation report message
sub _log_check {
    my $self = shift;
    my $testdir = "$self->{bfm}_tests";
    if ( (ref($self->{message}) eq 'ARRAY' && @{$self->{message}}==0 ) && (ref($self->{nomessage}) eq 'ARRAY' && @{$self->{nomessage}}==0 ) ) {
        push @{$self->{tests}},@{$self->{__tmp}};
        print "$debug: not check message in log files\n" if $Debug;
        return;
    }

    # corresponding log file exist -> message has value --> if match then select else !select
    #                              -> message has no value -> select
    # corresponding log file not exist -> !select
    ##
    # corresponding log file exist -> nomessage has value --> if match then reject else !reject
    #                              -> nomessage has no value -> !reject
    # corresponding log file not exist -> !reject

    foreach my $testcase (@{$self->{__tmp}}) {
        my $select =0;    # file not exist, default value
        my $reject =0;    # file not exist, default value
        my $savecase = $testcase;
        $testcase =~ s!^.*/$testdir/!!;
        $testcase =~ s!/!.!;
        $testcase = "$testdir.$testcase";
        my @logfile = glob("./log/$testcase.log ./log/$testcase-*.log");
        foreach my $file (@logfile) {
            if ( -e $file ) {
                $select=_filter($self->{message}, '',0);  # empty file
                $reject=_filterout($self->{nomessage},'',0); # empty file
                print "$debug: checking log files -- $file\n" if $Debug;
                my $fh = IO::File->new("<$file");
                while (my $line= $fh->getline()) {
                    $select=_filter($self->{message}, $line,0);
                    $reject=_filterout($self->{nomessage}, $line,0);
                    if ($reject) { # once reject, then exit loop
                        last;
                    }
                    elsif ($select) { # not default, then exit loop
                        if(ref($self->{message}) eq 'ARRAY'){
                            last if (@{$self->{message}})
                        }
                        else {
                            last if $self->{message};
                        }
                    }
                }
                $fh->close;
            }
            else {
                $select =0;
                $reject =0;
            }
            $savecase="$savecase -seed $1" if ($file =~ m{\./log/$testcase-(\d+)\.log});
            if ($select & !$reject) {
                push @{$self->{tests}},$savecase;
                print "$debug: message expected in ./log/$testcase.log\n" if $Debug;
            }
            else {
                push @{$self->{lefts}},$savecase;
                print "$debug: message unexpected in ./log/$testcase.log\n" if $Debug;
            }
        }

    }
    @{$self->{__tmp}}=();
}

## parameter $self->{filter}, $File::Find::name, $isdirectory
## nothing compare return value  1, compared with matching, return 1, compared not matching retrun 0,
## return 1 means select
sub _filter {
    my ($filter,$mixture,$subdir) = @_;
    my $match = 1;
    if (ref($filter) eq 'ARRAY') {
        foreach my $pat (@$filter) {
            $match = 0;
            if (($subdir && -e "$mixture/$pat") || (!$subdir && $mixture =~ m{$pat})) {
                $match = 1;
                last;
            }
        }
    }
    else {
        foreach my $pat ($filter) {
            $match = 0;
            if (($subdir && -e "$mixture/$pat") || (!$subdir && $mixture =~ m{$pat})) {
                $match = 1;
                last;
            }
        }
    }
    return $match;
}

# filter out
## nothing compare return value  0, compared with matching, return 1, compared not matching retrun 0,
## return 1 means reject
sub _filterout {
    my ($filterout,$mixture,$subdir) = @_;
    my $del = 0;
    if (ref($filterout) eq 'ARRAY') {
        foreach my $pat (@$filterout) {
            if (($subdir && -e "$mixture/$pat") || (!$subdir && $mixture =~ m{$pat})) {
                $del = 1;
                last;
            }
        }
    }
    else {
        foreach my $pat ($filterout) {
            if (($subdir && -e "$mixture/$pat") || (!$subdir && $mixture =~ m{$pat})) {
                $del = 1;
                last;
            }
        }
    }
    return $del;
}

# display class member, for debugging
sub _print_refarray {
    my $self = shift;
    my $member = shift;
    if(defined $self->{$member}) {
        if ( ref($self->{$member}) eq 'ARRAY' ) {
            print "$member => [";
            foreach (@{$self->{$member}}) {
                print "           $_\n";
            }
            print "]\n";
        }
        else {
            print "$member =>\'$self->{$member}\'\n";
        }
    }


}

1;
__END__

#-----------------------------------------------------------
=pod

=head1 NAME

Testbench::Regression -- get the test collection which meets the requirements.

=head1 SYNOPSIS

     use Testbench::Regression;
     my $reg=new Testbench::Regression(bfmdir=>'ppc',filterout=>'hdl', filter=>['spi','uart']);
     my @tests=$reg->gettests(); 
     print "@tests \n";
     $reg->display();

=head1 DESCRIPTION

Testbench::Regression is used for dealing with regression tests filter for soc verification.
Some Typical Applications are listed here:

     1) find out all the testcases do not have 'hdl' directory in  and 'defines.v' files, these testcases
        can skip compilation to run simulation directly.

        filterout=>['hdl','defines.v']

     2) find out all testcases not sucessfully finished. ie. no log file or log file not contains successful message
        nomessage=>['Test PASS', 'BOOT OK']

     3) find out gpu testcases
        filter=>'gpu'

=over 4

=item $reg = new Testbench::Regression(params)

Testbench::Regression Constructor support following parameters

     <> bfm    => cpm/scm/vmm       complete processor or systemc or vmm BFM model
     <> bfmdir => ppc/scenario      directory identifies testcase, up directory is testname  
     <> filter => []                filter the testcase with pattern 
     <> filterout => []             filter out the testcase with pattern 
     <> message => []               filter the testcase with message pattern in corresponding log file
     <> nomessage => []             filter out the testcase with message pattern in corresponding log file

     filter and filter out use both exact and ambiguous matching policy.
     Only directory contains bfmdir is exactly matching. for instance:

     ../cpm_tests/dmac contains 'arm' and 'hdl' directory,
     if bfmdir=>'arm', filter=>'hd' will not match ../cpm_tests/dma/hdl.
     you must use filter=>'hdl'. but filter=>'dma' will match ../cpm_tests/dmac.

     filter and filter out pattern are parallel, testcase are selected/deselect once one pattern matches.

=item @tests=$reg->gettests();

Return filtered array, filtered out array left in @{$reg->{lefts}};

=item $reg->display();

Display all class member for Debugging;

=item $reg->usage(verbose);

print out the usage in pod fomat which is compact(verbose=1) or detail (verbose=2)

=item @{$reg->{tests}};

all collected test cases which meet requirments;

=item @{$reg->{lefts}};

filtered out test cases which do not meet requirments;

=back

=head1 AUTHOR

I<Michael.Kang  E<lt>Chunlei.Kang@verisilicon.comE<gt>>

Copyright (c) 2011 Verisilicon Verification Group

=head1 SEE ALSO

I<Testbench::Run>

=head1 VERSION HISTORY

v1.0  initial version

=cut

 

提供的引用内容未涉及将regression中不同的uvm testbench coverage数据合并的方法。一般而言,在UVM(Universal Verification Methodology)中合并不同testbench的覆盖率数据,可借助仿真工具自身的功能达成。以下为通用步骤与示例代码: ### 1. 生成覆盖率数据文件 在仿真时,要确保生成覆盖率数据文件,通常为`.ucdb`(Unified Coverage Database)文件。在仿真命令里添加覆盖率相关选项: ```sh # 使用VCS仿真工具的示例 vcs -sverilog -cm line+cond+fsm+tgl your_testbench.sv your_design.v -l compile.log simv -cm line+cond+fsm+tgl -cm_name coverage_data -l sim.log ``` 上述命令会在仿真结束后生成`coverage_data.ucdb`文件。 ### 2. 合并覆盖率数据文件 借助仿真工具的覆盖率合并功能,把不同testbench生成的`.ucdb`文件合并成一个文件。以VCS为例: ```sh urg -full64 -format both -dir coverage_data_1.ucdb coverage_data_2.ucdb -dbname merged_coverage.ucdb ``` 此命令会把`coverage_data_1.ucdb`和`coverage_data_2.ucdb`合并成`merged_coverage.ucdb`文件。 ### 3. 查看合并后的覆盖率报告 合并完成后,可使用仿真工具查看合并后的覆盖率报告: ```sh urg -full64 -format both -dir merged_coverage.ucdb -report report_dir ``` 上述命令会在`report_dir`目录下生成可视化的覆盖率报告。 ### 代码示例 以下是一个简单的TCL脚本示例,用于自动化合并多个`.ucdb`文件: ```tcl # 定义要合并的覆盖率数据文件列表 set ucdb_files [list "coverage_data_1.ucdb" "coverage_data_2.ucdb" "coverage_data_3.ucdb"] # 合并覆盖率数据文件 exec urg -full64 -format both -dir {*}$ucdb_files -dbname merged_coverage.ucdb # 生成可视化报告 exec urg -full64 -format both -dir merged_coverage.ucdb -report report_dir ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值