#!/usr/bin/perl -w
###############################################################################
#
# Make a makefile for synthesis
#  Usage:
#   synth_make.pl [+incdir+DIR] [-y LIBDIR] [+libext+LIBEXT] verilog_files...
#
# This is an example of using rvp (rough verilog parser), it isn't mean to
#  be used for doing real synthesis!
#
# As usual there is no warranty!
#
# Costas
#
# $Header: /home/cc/v2html/rvp_scripts/RCS/synth_make.pl,v 1.4 2005/12/20 15:51:28 cc Exp $
###############################################################################

require rvp;
#use strict;

use vars qw($debug @files @inc_dirs @lib_dirs $lib_ext $vdb @hier_tops
            @db_files $m $f %global_done );

# defaults
$debug=0; 
@inc_dirs=('.');
@lib_dirs=();
$lib_ext='';

# process args
while ($_ = $ARGV[0]) {
    shift(@ARGV);
    if ( /^-y$/ ) { 
	&usage("$_ needs an arguement") if ($#ARGV < 0);
	push(@lib_dirs,shift(@ARGV));
	next; 
    }
    elsif ( /^\+incdir\+(.+)$/ ) { 
	push(@inc_dirs,$1);
	next; 
    }
    elsif ( /^\+libext\+(.+)$/ ) { 
	$lib_ext=$1;
	next; 
    }
    else {
	($f=$_) =~ s|^.*/||;
	push(@files,$_);
    }
}

die "Usage $0 [+incdir+DIR] [-y LIBDIR] [+libext+LIBEXT] verilog_files..." unless @files;

print "# This makefile was automatically generated by $0\n";

print "\n";

# pass in: list of files on command line
#          empty list of global includes []
#          empty hash of predefined defines {}
#          and set quiet to be quiet (1)
#          then incdirs, libdirs, libext
$vdb = rvp->read_verilog(\@files,[],{},1,\@inc_dirs,\@lib_dirs,$lib_ext);
my @problems = $vdb->get_problems();
if (@problems) {
    foreach my $problem ($vdb->get_problems()) {
	print STDERR "$problem.\n";
    }
    # die "Warnings parsing files!";
}


print "#  Source files scanned:\n";
print "#  ".join("\n#  ",$vdb->get_files()) . "\n\n";

# find modules at the top of the hierarchy
foreach $m (sort $vdb->get_modules()) {
    print "  checking if module $m is a top\n" if $debug;
    if  (! $vdb->get_first_instantiator($m)) {
	print "      it is!\n" if $debug;
	push(@hier_tops,$m);
    }
}

# first target is all modules at top of hierarchy
print "all:";
foreach $m (@hier_tops) {    print " $m.db"; }
print "\n\n";

# now do all the dependencies working down the hierarchy
foreach $m (@hier_tops) { 
    do_deps($vdb,$m);
}

# Print a list of DB files and the clean rule
print "DB_FILES=".join(" ",@db_files)."\n\n";

print "clean:\n";
print "\trm -f ".'${DB_FILES} ${DB_FILES:db=synlog}'."\n\n";

exit 0;

#################################################################################
#
# Subroutines

sub do_deps {
    my ($vdb,$m) = @_;
    my ($f,@clocks,$sig,$s_line,$s_a_line,$s_i_line,$s_type,$s_file,$s_posedge,$s_negedge,
	$inc,%done,@instances,$imod,$mf,$iname,$l,$ff,
	$file_list,$clks,@submods,%inc_done,@traverse,$mm);

    ($f) = $vdb->get_modules_file($m);
    if (! $f) {
	print "Warning: Couldn't find file for module $m\n";
	return;
    }

    # find clocks
    @clocks = ();
    foreach $sig ($vdb->get_modules_signals($m)) {
    	if (($s_line,$s_a_line,$s_i_line,$s_type,$s_file,$s_posedge,$s_negedge) = 
    	    $vdb->get_module_signal($m,$sig)) {
    	    print "Checking $sig for clockiness ($s_posedge $s_negedge)\n" if $debug;
    	    push (@clocks, $sig ) if ($s_posedge);
    	    print STDERR "Warning: can't handle negedge clocks\n" if ($s_negedge);
    	}
    }

    # Print out the clocks you could probabbly do something cleverer
    if (@clocks) {
	print "# Clocks in this module: @clocks\n";
    }

    # print the target name
    print "$m.db: ";

    # print the dependencies
    #   print the source file's full name
    print "" . $vdb->get_files_full_name($f);
    #   print a list of all the included files
    foreach $inc ($vdb->get_files_includes($f)) {
	if (!exists($inc_done{$inc})) {
	    print " " . $vdb->get_files_full_name($inc);
	    $inc_done{$inc}=1;
	}
    }

    # add this db file to the list for cleaning
    push(@db_files,"$m.db");
    
    undef(%done);
    @instances = ();
    @submods = ();

    # do a list of .db files it depends on
    #  go through all of the things this modules instantiates
    for (($imod,$mf,$iname,$l) = $vdb->get_first_instantiation($m );
	 $imod;
	 ($imod,$mf,$iname,$l) = $vdb->get_next_instantiation()) {
	push(@instances,$iname);
	# Only print the dependency once for each submodule
	if (!exists($done{$imod})) {
	    $done{$imod} = $iname;
	    print " $imod.db";
	}
	# only push this onto the submods list if it
	#  hasn't already been done before (anywhere)
	if (!exists($global_done{$imod})) {
	    $global_done{$imod}=1;
	    push(@submods,$imod);
	}
    }

    print "\n";
    # now print out the command to run, just assume there's a script for
    #  each module called module.scr
    print "\tdc_shell -f $m.scr > $m.synlog\n";
    print "\n";

    # now do all the submodules
    foreach $imod (sort @submods) {
	do_deps($vdb,$imod);
    }

}


