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

#require 5.006_001;
use Getopt::Long;
use IO::File;
use Pod::Usage;
use strict;
use vars qw ($Debug);

our @Items;

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

$Debug = 0;
my $Opt_Srcdir = ".";
Getopt::Long::config ("pass_through", "no_auto_abbrev");
if (! GetOptions (
	  "help"	=> \&usage,
	  "debug"	=> sub { $Debug = 1; },
	  "srcdir=s"	=> \$Opt_Srcdir,
	  "<>"		=> sub { die "%Error: Unknown parameter: $_[0],"; },
    )) {
    usage();
}

read_keys("$Opt_Srcdir/../include/verilated_cov_key.h");
lint();
write_keys("$Opt_Srcdir/../include/verilated_cov_key.h");

#----------------------------------------------------------------------

sub usage {
    pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
    exit (1);
}

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

sub read_keys {
    my $filename = shift;

    my $fh = IO::File->new("<$filename") or die "%Error: $! $filename,";
    while (defined (my $line = $fh->getline())) {
	$line =~ s/\/\/.*$//;
	next if $line =~ /^\s*$/;
	if ($line =~ /^\s*VLCOVGEN_ITEM/) {
	    $line =~ /^\s*VLCOVGEN_ITEM *\( *"([^"]+)" *\)/
		or die "%Error: $filename:$.: Misformed VLCOVGEN_ITEM line,";
	    my @data;
	    my $code = "\@data = ($1);";
	    eval $code;
	    die "%Error: $filename:$.: Parsing '$code': $@," if $@;
	    push @Items, {@data};
	}
    }
}

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

sub lint {
    my %shorts;
    my $ok = 1;
    foreach my $itemref (@Items) {
	if ($shorts{$itemref->{short}}) {
	    warn "%Error: Duplicate short code: $itemref->{short},";
	    $ok = 0;
	}
	$shorts{$itemref->{short}} = 1;
    }
    return $ok;
}

sub write_keys {
    my $filename = shift;

    my $fh = IO::File->new("<$filename") or die "%Error: $! $filename\n";

    my @in;
    my @out;
    my $deleting;
    while (defined(my $line = $fh->getline)) {
	push @in, $line;
	if ($line =~ /VLCOVGEN_CIK_AUTO_EDIT_BEGIN/) {
	    $deleting = 1;
	    push @out, $line;
	    foreach my $keyref (sort {$a->{name} cmp $b->{name}} @Items) {
		push @out, sprintf("#define VL_CIK_%s \"%s\"\n",
				   uc $keyref->{name}, $keyref->{short});
	    }
	}
	elsif ($line =~ /VLCOVGEN_SHORT_AUTO_EDIT_BEGIN/) {
	    $deleting = 1;
	    push @out, $line;
	    foreach my $keyref (sort {$a->{name} cmp $b->{name}} @Items) {
		push @out, sprintf("\tif (key == \"%s\") return VL_CIK_%s;\n",
				   $keyref->{name}, uc $keyref->{name});
	    }
	}
	elsif ($line =~ /VLCOVGEN_.*AUTO_EDIT_END/) {
	    $deleting = 0;
	    push @out, $line;
	}
	elsif ($deleting) {
	}
	else {
	    push @out, $line;
	}
    }
    $fh->close;

    my $ok = join("", @out) eq join("", @in);
    if (!$ok) {
	my $fh = IO::File->new(">$filename") or die "%Error: $! writing $filename\n";
	$fh->print(join "", @out);
	$fh->close;
    }
}


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

=pod

=head1 NAME

vlcovgen - Generate verilated_cov headers to reduce C++ code duplication

=head1 SYNOPSIS

  (called from make rules)
  vlcovgen

=head1 DESCRIPTION

Generates several files for Verilator compilations.

=head1 ARGUMENTS

=over 4

=item --help

Displays this message and program version and exits.

=back

=head1 DISTRIBUTION

Copyright 2002-2017 by Wilson Snyder.  Verilator 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.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
more details.

=head1 AUTHORS

Wilson Snyder <wsnyder@wsnyder.org>

=head1 SEE ALSO

=cut

######################################################################
### Local Variables:
### compile-command: "./vlcovgen --srcdir ."
### End:
