#!/usr/bin/perl -w
# See copyright, etc in below POD section.
######################################################################

use Getopt::Long;
use Cwd;
use IO::File;
use Pod::Usage;
use strict;
use vars qw ($Debug);

#======================================================================
# main

our $Opt_Stage = 0;

autoflush STDOUT 1;
autoflush STDERR 1;
Getopt::Long::config ("no_auto_abbrev");
if (! GetOptions (
	  "debug"	=> sub { $Debug = 1; },
	  "<>"		=> sub { die "%Error: Unknown parameter: $_[0]\n"; },
	  "stage=i"	=> \$Opt_Stage,
    )) {
    die "%Error: Bad usage, try 'install_test --help'\n";
}

test();

#######################################################################

sub test {
    -r "nodist/install_test" or die "%Error: Run from the top of the verilator kit,";

    cleanenv();
    $ENV{VERILATOR_NO_OPT_BUILD} = 1;   # Don't build optimized executables; just slows this down
    run("make distclean") if -r "Makefile";

    # Try building from a scratch area
    my $srcdir = getcwd();
    my $blddir  = $srcdir."/test_regress/obj_dir/install_test_bld";
    my $prefix  = $srcdir."/test_regress/obj_dir/install_test_prefix";
    my $testdirp= $srcdir."/test_regress/obj_dir/install_test_testp";
    my $testdirn= $srcdir."/test_regress/obj_dir/install_test_testn";

    if ($Opt_Stage <= 0) {
	run("/bin/rm -rf $blddir");
	run("/bin/mkdir -p $blddir");
	run("cd $blddir && $srcdir/configure --prefix $prefix");
	run("cd $blddir && make -j");
    }

    # Install it under the prefix
    if ($Opt_Stage <= 1) {
	run("/bin/rm -rf $prefix");
	run("/bin/mkdir -p $prefix");
	run("cd $blddir && make install");
	run("test -e $prefix/share/man/man1/verilator.1");
	run("test -e $prefix/share/verilator/examples/test_c/Makefile");
	run("test -e $prefix/share/verilator/include/verilated.h");
	run("test -e $prefix/bin/verilator");
	run("test -e $prefix/bin/verilator_bin");
	run("test -e $prefix/bin/verilator_bin_dbg");
	run("test -e $prefix/bin/verilator_profcfunc");
    }

    # Run a test using just the path
    if ($Opt_Stage <= 2) {
	my $dir = $testdirp;
	run("/bin/rm -rf   $dir");
	run("/bin/mkdir -p $dir");
	my $bin1 = $prefix."/bin";
	my $bin2 = $prefix."/share/bin";
	write_verilog($dir);
	run("cd $dir && PATH=$bin1:$bin2:\$PATH verilator --cc foo.v --exe foo.cpp");
	run("cd $dir/obj_dir && PATH=$bin1:$bin2:\$PATH make -f Vfoo.mk");
	run("cd $dir && PATH=$bin1:$bin2:\$PATH obj_dir/Vfoo");
    }

    # Run a test using exact path to binary
    if ($Opt_Stage <= 3) {
	my $dir = $testdirn;
	run("/bin/rm -rf   $dir");
	run("/bin/mkdir -p $dir");
	write_verilog($dir);
	my $bin1 = $prefix."/bin";
	my $bin2 = $prefix."/share/bin";
	run("cd $dir && $bin1/verilator --cc foo.v --exe foo.cpp");
	run("cd $dir/obj_dir && make -f Vfoo.mk");
	run("cd $dir/obj_dir && ./Vfoo");
    }
}

sub write_verilog {
    my $dir = shift;
    IO::File->new(">$dir/foo.v")->print('module t; initial begin $display("HELLO WORLD"); $finish; end endmodule'."\n");
    my $fh = IO::File->new(">$dir/foo.cpp");
    $fh->print('#include "Vfoo.h"'		,"\n");
    $fh->print('unsigned int main_time = 0;'	,"\n");
    $fh->print('double sc_time_stamp () {'	,"\n");
    $fh->print('    return main_time;'		,"\n");
    $fh->print('}'				,"\n");
    $fh->print('int main() {'			,"\n");
    $fh->print('    Vfoo *top = new Vfoo;'	,"\n");
    $fh->print('    while (!Verilated::gotFinish()) {',"\n");
    $fh->print('	top->eval();'		,"\n");
    $fh->print('	main_time++;'		,"\n");
    $fh->print('    }'				,"\n");
    $fh->print('    top->final();'		,"\n");
    $fh->print('}'				,"\n");
}

sub cleanenv {
    foreach my $var (keys %ENV) {
	if ($var eq "VERILATOR_ROOT") {
	    print "unset $var # Was '$ENV{$var}'\n";
	    delete $ENV{$var}
	}
    }
}

#######################################################################

sub run {
    # Run a system command, check errors
    my $command = shift;
    print "\t$command\n";
    system "$command";
    my $status = $?;
    ($status == 0) or die "%Error: Command Failed $command, $status, stopped";
}

#######################################################################
__END__

=pod

=head1 NAME

install_test - Build and install Verilator several ways

=head1 SYNOPSIS

  install_test

=head1 DESCRIPTION

install_test performs several make-and-install iterations to verify the
kit.  It isn't part of the normal "make test" due to the number of builds
required.

=head1 ARGUMENTS

=over 4

=item --help

Displays this message and program version and exits.

=back

=head1 DISTRIBUTION

Copyright 2009-2012 by Wilson Snyder.  This package is free software; you
can redistribute it and/or modify it under the terms of either the GNU
Lesser General Public License Version 3 or the Perl Artistic License
Version 2.0.

=head1 AUTHORS

Wilson Snyder <wsnyder@wsnyder.org>

=head1 SEE ALSO

=cut

######################################################################
### Local Variables:
### compile-command: "cd .. ; nodist/install_test "
### End:
