#! /usr/local/bin/perl
#
# maketnm -- make template .tnm file based on XFF file
#
# maketnm [-f] [-r] [-p] <design>
#
# revision 2.4

$script_name    = "maketnm";
$script_version = "2.3.2";

print( "$script_name Version $script_version\n" );
print( "(c) Copyright 1994-1995 Xilinx Inc. All rights reserved.\n\n" );

&usage() if ( ! @ARGV );

#
# process arguments
#
$bad_args = 0;

$ffs  = 0;
$rams = 0;
$pads = 0;

foreach $arg ( @ARGV )
{
  if ( $arg =~ m|^-(\S+)$| )
  {
    if ( $1 eq "f" )
    {
      $ffs = 1;
    }
    elsif ( $1 eq "r" )
    {
      $rams = 1;
    }
    elsif ( $1 eq "p" )
    {
      $pads = 1;
    }
    else
    {
      print( "$script_name: ERROR: option $1 not recognized.\n" );
      ++$bad_args;
    }
  }
  elsif ( ! $base )
  {
    $base = $arg;
  }
  else
  {
    print( "$script_name: ERROR: extra file name $arg specified.\n" );
    ++$bad_args;
  }
}

if ( $bad_args != 0 )
{
  print( "$script_name: ERROR: could not process $bad_args argument(s)\n" );
  &usage();
}

if ( ( $ffs + $rams + $pads ) == 0 ) # none specified, use all types
{
  $ffs  = 1;
  $rams = 1;
  $pads = 1;
}

#
# define file names
#
if ( $base =~ /\./ )
{
  $base = substr( $base, 0, rindex( $base, "." ) );
}

if ( ! -e ( $xff_file = $base.".xff" ) )
{
  die( "$script_name: ERROR: $xff_file does not exist.\n\n" );
}
$out_file = $base.".tt";

#
# record timestamp
#
$got_pkg = eval( "require( \"ctime.pl\" )" );
if ( defined( $got_pkg ) && $got_pkg )
{
  $timestamp = &ctime( time );
  chop $timestamp;
}

#
# initialize template file
#
open( OUT, ">".$out_file ) || die;

print( OUT "# $out_file -- created by $script_name : $timestamp\n" );
print( OUT "#\n\n" );

#
# parse XFF file
#
open( XFF, $xff_file ) || die;

print( "$script_name: processing XFF file $xff_file ...\n" );

@ff_list  = ();
@ram_list = ();
@pad_list = ();

while ( <XFF> )
{
  chop;

  #
  # process SYM records
  #
  if ( m|^\s*SYM\s*,\s*([^,]+)\s*,\s*([^,]+)\s*,*\s*(.*)$|i )
  {
    ( $symname, $symtype, $symparams ) = ( $1, $2, $3 );

    if ( &is_flop( $symtype ) && $ffs ) # found a flip-flop SYM record
    {
      push( @ff_list, $symname );
    }
    elsif ( $symtype eq "RAM" && $rams ) # found a RAM
    {
      push( @ram_list, $symname );
    }
  }
  #
  # process EXT records
  #
  elsif ( m|^\s*EXT\s*,\s*([^,]+)\s*,\s*(.)\s*,?\s*([^,]*)\s*,?\s*(.*)$|i )
  {
    ( $padname, $paddir, $pinnum, $extparams ) = ( $1, $2, $3, $4 );

    if ( $pads )
    {
      push( @pad_list, $padname );
    }
  }
}

close( XFF );

#
# create template file
#
print( OUT "#\n# flip-flops\n#\n\n" ) if ( @ff_list );
foreach $name ( sort( @ff_list ) )
{
  printf( OUT "FFS  %s : \n", $name );
}

print( OUT "\n#\n# RAMs\n#\n\n" ) if ( @ram_list );
foreach $name ( sort( @ram_list ) )
{
  printf( OUT "RAMS %s : \n", $name );
}

print( OUT "\n#\n# I/O pads\n#\n\n" ) if ( @pad_list );
foreach $name ( sort( @pad_list ) )
{
  printf( OUT "PADS %s : \n", $name );
}

close( OUT );

print( "$script_name: template .tnm file written to $out_file ...\n\n" );


#---------------------------------------------------------------------------
#
# is_flop( symtype )
#
#   return true if symbol type represents a flip-flop
#   (including FFS-type XBLOX symbols)
#
sub is_flop
{
  local( $symtype ) = @_;

  ( $symtype eq "DFF" )
  || ( $symtype eq "INFF" )
  || ( $symtype eq "INLAT" )
  || ( $symtype eq "INREG" )
  || ( $symtype eq "OUTFF" )
  || ( $symtype eq "OUTFFT" )
  || ( $symtype eq "ACCUM" )
  || ( $symtype eq "SHIFT" )
  || ( $symtype eq "COUNTER" )
  || ( $symtype eq "DATA_REG" )
  || ( $symtype eq "CLK_DIV" );
}

#---------------------------------------------------------------------------
#
# usage()
#
sub usage
{
  print( "usage: maketnm [-f] [-r] [-p] <design>\n\n" );
  print( "-f : include flip-flops in template\n" );
  print( "-r : include RAMs in template\n" );
  print( "-p : include I/O pads in template\n\n" );
  print( "use no options to include all three types\n" );
  die( "\n" );
}
