blob: fcb090a84715ea233a407caa63e4373ac8fa4682 [file] [log] [blame]
eval 'exec perl -S $0 ${1+"$@"}'
if 0;
# -*- mode: cperl -*-
#----------------------------------------------------------------------
# Copyright 2007-2010 Cadence Design Systems, Inc.
# Copyright 2010 Synopsys Inc.
# Copyright 2010 Mentor Graphics Corporation
# All Rights Reserved Worldwide
#
# Licensed under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in
# writing, software distributed under the License is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See
# the License for the specific language governing
# permissions and limitations under the License.
#----------------------------------------------------------------------
#use strict;
use warnings;
use Getopt::Long;
use File::Find;
use Cwd;
use Fcntl;
use File::Temp qw/tempfile tempdir/;
use File::Path;
use File::Copy;
use Data::Dumper;
use File::stat;
# Tar module may not be available
if (eval {require Archive::Tar; 1;}) {
$Tar_Pm = 1;
}
my @all_files=();
my %content=();
local $opt_marker="-*-";
local $opt_help;
local $opt_backup;
local $opt_write;
local $opt_all_text_files;
local $opt_tar_exec="tar";
# regexp to match sv files (can be overriden using --sv_ext)
local $opt_sv_ext="\.(s?vh?|inc)\$";
# regexp of mime types for files considered for a change with the --all option
local $text_file_mime_regexp="(text\/|application\/x-shellscript|regular file)";
# ignore pattern
local $file_ignore_pattern="(/(.hg|.git|INCA_libs|.daidir|.vdb|simv|csrc|DVEfiles)\/|[#~]\$|\.(zip|gz|bz2|orig|diff|patch)\$)";
my $VerID='-*- $Id: ovm2uvm.pl,v d60c9fc172de 2010/10/13 14:58:52 accellera $ -*-';
my @Options=(
["help","this help screen"],
["top_dir=s","the top directory name containing the files to translate"],
["backup","if specified make a backup of all files handled by the script"],
["write","really write the changed files back to disk (by default it runs in dry mode)"],
["marker=s", "use the marker supplied instead of the default marker [$opt_marker]"],
["sv_ext=s","a regexp matching all sv files default:[$opt_sv_ext]"],
["all_text_files","apply the simple \"o2u\" transformation to all files where the MIME-type of matches [$text_file_mime_regexp]"],
["tar_exec=s","the script assume a gtar compatible tar, if your gtar compatible tar is not avail point to it via --tar_exec"]
);
if(!GetOptions(map ( @$_[0], @Options))) {
ErrorMessage("Error during option parsing");
}
if (defined $opt_help) { PrintUsage(@Options); exit(1);}
if(!$opt_top_dir) { $opt_top_dir= getcwd;}
$opt_top_dir =~ s/\/$//;
$DUMMY='-' x 80;
NoteMessage("$DUMMY");
NoteMessage("$VerID");
NoteMessage("traversing directory [$opt_top_dir] to find files");
NoteMessage("-*- this script requires a gtar compatible tar to make backups -*-");
search_all_relevant_files($opt_top_dir);
#
#
#
foreach my $file (@all_files) {
if($file =~ /${opt_sv_ext}/) {
print "handling sv [$file]\n";
$content{$file}=ReadFileAsText($file);
$content{$file}=replace_trivial($content{$file},$file);
} elsif (defined($opt_all_text_files) && matches_mime_type($file)) {
print "handling generic [$file]\n";
$content{$file}=ReadFileAsText($file);
$content{$file}=simple_fix($content{$file});
} else {
print "skipping $file ...\n";
}
}
write_back_files(%content);
# determines if the file is one of requested mime types
sub matches_mime_type {
my($file) = @_;
my($mime)=qx{file -i $file};
if($mime =~ /:\s+${text_file_mime_regexp}/) {
return 1;
} else {
return 0;
}
}
# writes back the contents of the files
sub write_back_files {
my(%content)=@_;
# now write it back
my $tempdir=tempdir(CLEANUP => 1);
NoteMessage("writing file to new top_dir $tempdir");
foreach $f (keys %content) {
my($nfile)=$f;
$nfile=~ s/^$opt_top_dir/$tempdir/;
my ($volume,$directories,$file) = File::Spec->splitpath( $nfile );
mkpath($directories, 0);
open(OUT,">$nfile") || die("error opening $nfile fullfile:$f for write [$!]");
print OUT $content{$f};
close(OUT);
}
NoteMessage("the patch is avail as [ovm2uvm_$$.patch] for inspection");
system("diff -r $opt_top_dir $tempdir > ovm2uvm_$$.patch");
if($opt_backup) {
NoteMessage("making backup of current files before writing back in [ovm2uvm_back_$$.tar.gz]");
if ($Tar_Pm) {
my $tar=Archive::Tar->new;
$tar->add_files(keys(%content));
$tar->write("ovm2uvm_back_$$.tar.gz",COMPRESS_GZIP);
} else {
my($fh,$fname) = tempfile();
print $fh join("\n",keys(%content));
system "$opt_tar_exec cf - -T $fname | gzip -9v > ovm2uvm_back_$$.tar.gz";
}
}
if($opt_write) {
NoteMessage("now writing back to changes (some files might be written back with changed filenames [*ovm* -> *uvm*]");
foreach $f (keys %content) {
my($nfile)=$f;
$nfile=~ s/^$opt_top_dir//;
my($mod_nfile)=simple_fix($nfile);
my($target)=$f;
my($source)=$f;
$source=~ s/^$opt_top_dir/$tempdir/;
if($mod_nfile ne $nfile) {
WarnMessage("filename of [$f]=top_dir[$opt_top_dir][$nfile] got changed, its now [$opt_top_dir][$mod_nfile]");
unlink $f;
$target=$opt_top_dir . $mod_nfile;
}
warn("target file $target is not writeable and in the way") if (-e $target && !(-w $target));
#NoteMessage("moving [$source] to [$target]");
move($source,$target);
}
}
}
sub search_all_relevant_files {
my ($dir) = @_;
finddepth({ wanted => \&pattern, no_chdir => 1 }, $dir);
}
sub replace_trivial{
my($t,$fname) = @_;
# FIX deprecated macros OVM_REPORT_*
$t =~ s/\`OVM_REPORT_(WARNING|ERROR|FATAL)/sprintf("\`uvm_%s",lc($1))/ge;
# FIX deprecated 'OVM_REPORT_INFO now needs a UVM_NONE in the end
$t =~ s/\`OVM_REPORT_INFO(.*?)\)/\`uvm_info$1,UVM_MEDIUM)/g;
# FIX somecomponent::global_stop_request() -> (global) global_stop_request()
$t =~ s/\S+::global_stop_request/global_stop_request/g;
# FIX instancehandle.global_stop_request() -> (global) global_stop_request()
$t =~ s/(\S+\.)global_stop_request/global_stop_request/g;
# FIX take remove arg2,arg3 from constructor ovm_sequence::new(,arg2,arg3)
while($t=~ /extends\s+ovm_sequence\s*;.*?endclass/s) {
($pre,$b,$post) =($`,$&, $');
$b =~ s/super\.new\(([^,\n]+),(.*);/super.new($1); \/\/ NOTE: [$&]/;
$b =~ s/ovm_sequence/uvm_sequence/g;
$t = $pre . $b . $post;
}
# FIX take remove arg2,arg3 from constructor ovm_sequence_item::new(,arg2,arg3)
while($t=~ /extends\s+ovm_sequence_item\s*;.*?endclass/s) {
($pre,$b,$post) =($`,$&, $');
$b =~ s/super\.new\(([^,\n]+),(.*);/super.new($1); \/\/ NOTE: [$&]/;
$b =~ s/ovm_sequence_item/uvm_sequence_item/g;
$t = $pre . $b . $post;
}
# MARKER include of ovm private files
$t =~ s/include\s+\"ovm_(?!macros).*?\.svh\".*/$& \/\/ $opt_marker FIXME include of ovm file other than ovm_macros.svh detected, you should move to an import based methodology/g;
# FIX `message(sev,(...)) -> uvm_info("FIXME","...",sev)
$t =~ s|(?s)\`message\(([^,]+),\s*\(\s*\$psprintf\((.*?)\)\s*\)\s*\)|\`uvm_info("FIXME",\$sformatf($2),$1)|g;
$t =~ s|(?s)\`message\(([^,]+),\s*\(\s*\$sformatf\((.*?)\)\s*\)\s*\)|\`uvm_info("FIXME",\$sformatf($2),$1)|g;
$t =~ s|(?s)\`message\(([^,]+),\s*\((.*?)\)\s*\)|\`uvm_info("FIXME",\$sformatf($2),$1)|g;
$t =~ s|(?s)\`message\(([^,]+),\s*(.*?)\)|\`uvm_info("FIXME",\$sformatf($2),$1)|g;
# FIX ovm_factory::print() -> factory.print
$t =~ s/ovm_factory::print\(\)/factory.print()/g;
# FIX ovm_factory:: set_type_override -> factory. set_type_override_by_name ()
$t =~ s/ovm_factory::set_type_override_by_name/factory.set_type_override_by_name/g;
$t =~ s/ovm_factory::set_type_override_by_type/factory.set_type_override_by_type/g;
$t =~ s/ovm_factory::set_type_override\(/factory.set_type_override_by_name(/g;
# FIX `dut_error(MSG) -> uvm_error
$t =~ s/(?s)\`dut_error\(\((.*?)\)\s*\)/\`uvm_error(\"DUT\",\$psprintf($1))/g;
$t =~ s/(?s)\`dut_error\((.*?)\)/\`uvm_error(\"DUT\",$1)/g;
# FIX ovm_msg_detail(XX) -> uvm_report_enabled(XXX)
$t =~ s/(?s)\`ovm_msg_detail\((.*?)\)/uvm_report_enabled($1)/g;
# FIX set_global_verbosity(..) -> set_report_...
$t =~ s/ovm_urm_report_server::set_global_verbosity\((.*)\);/uvm_pkg::uvm_top.set_report_verbosity_level_hier($1)/g;
# MARKER _urm_
$t =~ s/_urm_.*/$& \/\/ $opt_marker FIXME potential deprecated URM reference\n/g;
# MARKER _avm_
$t =~ s/_avm_.*/$& \/\/ $opt_marker FIXME potential deprecated AVM reference\n/g;
# FIX+MARKER .ovm_enable_print_topology -> .enable_print_topology
$t =~ s/\S+\.[ou]vm_enable_print_topology(.*)/uvm_top.enable_print_topology$1 \/\/ $opt_marker NOTE mapped from $& \n/g;
$t =~ s/(?<!\.)[ou]vm_enable_print_topology(.*)/uvm_top.enable_print_topology$1 \/\/ $opt_marker NOTE mapped from $& \n/g;
# FIX ovm_print_topology() -> uvm_top.print()
$t =~ s/ovm_print_topology/uvm_top.print/g;
# MARKER configure_ph -> end_of_elaboration
$t =~ s/configure_ph.*/$& \/\/ $opt_marker FIXME potential usage of configure_ph, this should be mapped to end_of_elaboration_ph\n/g;
# FIX ovm_reporter -> uvm_report_object
$t =~ s/ovm_reporter/uvm_report_object/g;
# FIX+MARKER ovm_template.svh is gone
$t =~ s/\`include\s+\"ovm_templates\.svh\".*/\/\/ $opt_marker NOTE this doe not exist anymore in UVM $&\n/g;
# FIX cdns_recording.svh has been replaced by package for uvm
$t =~ s/\`include\s+\".*cdns_recording.*\".*/\/\/ $opt_marker NOTE please contact cadence support for an updated package $&\n/g;
# MARKER OVM_FIELD_DATA is a private macro to the ovm library and deprecated, if its a must it might be replaced with M_UVM_FIELD_DATA
$t =~ s/\`OVM_FIELD_DATA/\`M_UVM_FIELD_DATA/g;
$t =~ s/M_UVM_FIELD_DATA.*/$& \/\/ $opt_marker NOTE OVM_FIELD_DATA is a private macro to the ovm library and deprecated, in legacy code it might be replaced with M_UVM_FIELD_DATA\n/g;
# FIX map raise|drop objection argument mix
# first swap with 3 args
$t =~ s/\.(drop|raise)_objection\(([^,;]+),([^,;]+),([^,;]+)\)\s*;/.$1\_objection($2,$4,$3);/g;
# then swap those with two args
$t =~ s/\.(drop|raise)_objection\(([^,;]+),([^,;]+)\)\s*;/.$1\_objection($2,,$3);/g;
# FIX ovm_factory::print_all_overrides() -> factory.print()
$t =~ s/ovm_factory::print_all_overrides\(\)/factory.print()/g;
# FIX+MARKER seq_item_prod_if -> seq_item_port
$t =~ s/seq_item_prod_if.*/$& \/\/ $opt_marker NOTE seq_item_prod_if has been replaced with seq_item_port \n/g;
$t =~ s/seq_item_prod_if/seq_item_port/g;
# FIX+MARKER seq_item_cons_if -> seq_item_export
$t =~ s/seq_item_cons_if.*/$& \/\/ $opt_marker NOTE seq_item_cons_if has been replaced with seq_item_export \n/g;
$t =~ s/seq_item_cons_if/seq_item_export/g;
# FIX seq_item_port.connect_if -> seq_item_port.connect
$t =~ s/(seq_item_port\.connect)_if/$1/g;
# FIX ovm_threaded_component -> uvm_component
$t =~ s/ovm_threaded_component/uvm_component/g;
# FIX post_new->build, pre_run->start_of_simulation
$t =~ s/post_new\s*\(\)/build()/g;
$t =~ s/pre_run\s*\(\)/start_of_simulation()/g;
# MARKER (import+export)_connections do not exist anymore and have beein mapped to connect()
$t =~ s/(export|import)_connections.*/$& \/\/ $opt_marker NOTE $1 _connections has been deprecated and should be mapped into connect()/g;
# FIX the simple O -> U changes
$t=simple_fix($t);
$t;
}
sub simple_fix {
my($t)=@_;
$t =~ s/ovm/uvm/g;
$t =~ s/tlm/uvm_tlm/g;
$t =~ s/OVM/UVM/g;
$t =~ s/TLM_/UVM_TLM_/g;
$t;
}
sub pattern {
my($filename)= $File::Find::name;
my($st) =stat($filename) || die "error: $filename: $!";
# print "[$filename][$st]";
# print Dumper($filename);
# print Dumper($st),"\n";
# NOTE directories are not handled (a directory ovm_bla has to be renamed manually)
return 0 if (-d $filename);
warn("file $filename is a link and may lead to strange results") if -l $filename;
return 0 if $filename =~ /${file_ignore_pattern}/;
# return unless $filename =~ /\.s?vh?$/;
# replace_string($filename);
push @all_files,$filename;
}
sub PrintUsage {
my(@Options)=@_;
while(<DATA>){
print $_;
}
my($txt);
print "supported transformations\n";
$txt = ReadFileAsText($0);
while($txt =~ /#\s+(FIX|MARKER|TODO)(.*?)\n/gs) {
print "action:$1\t\tdescription: $2\n";
}
print "\n\noptions:\n\n";
foreach $i (@Options) {
printf("\t--%-20s\t\t@$i[1]\n",@$i[0]);
}
}
sub ReadFileAsText {
my($FILENAME)=@_;
my(@FILES)=();
my($FILE,$TEXT);
local(*INFILE);
# DebugMessage("1trying to read text-file [$FILENAME]");
$TEXT="";
foreach $FILE (glob($FILENAME)) {
# DebugMessage("2trying to read text-file [$FILE]");
open(INFILE,$FILE) || WarnMessage("can't open file [$FILE]");
undef $/;
$TEXT .= <INFILE>;
$/ = "\n";
close(INFILE);
}
return ($TEXT);
}
sub WarnMessage{
my($Line)=@_;
Message("warning",$Line);
}
sub ErrorMessage{
my($Line)=@_;
Message("error",$Line);
die "$0 stopped\n";
}
sub NoteMessage{
my($Line)=@_;
Message("note",$Line);
}
sub Message {
my($Level,$Line)=@_;
print STDERR "$Level $Line\n";
}
__DATA__
This scripts walks through all files under the --top_dir hierarchy and makes modifications
so that the OVM code fragments are changed to their UVM counterparts. As it is based on perl/regexps rather
then a full parsing some of the replacements might be inaccurate or it might not find all occurences required
to change. however it is expected that ~90%+ of the changes required in a conversion are completed by the script.
standard usage model sv files only:
1. run the script with the --top_dir option
2. inspect the changes made in the produced *.patch file
3. enable automatic write-back by supplying --write to the command invocation
(under some circumstances filenames get changed (when they contain either *ovm* or *OVM*))
4. inspect the MARKERS
usage: ovm2uvm.pl options* args*
example: ovm2uvm.pl --top_dir /xyz/abc/src
all_text_files use model:
If the all_text_files use model is enabled using the --all_text_files switch all files recognized
as text files are additionally considered for replacements. The simple o-to-u replacements will be performed
in all files (textual + sv) while the SV/OVM specific changes will be only applied to files identified as SV.
example: example: ovm2uvm.pl --top_dir /xyz/abc/src --all