NAME

SPP (Synopsys Plus Perl) - A Perl interface to Synopsys' shells

SYNOPSIS

  #!/usr/local/bin/perl -w

  use strict;
  use Synopsys;

  $Synopsys::Verbose = 1;

  my $shell = Synopsys->new('dc_shell', '-tcl_mode')
                or die "Init of dc_shell failed, exiting.\n";

  $shell->variable('search_path', '.', '$synopsys_root/libraries/syn');
  $shell->variable('link_library', '*', 'lcb500kiov.db', 'lcb500kv.db');

  $shell->read_verilog('BigChip.v');

  my $cells = $shell->get_pins("-h *");

  ....

  $shell->exit;

DESCRIPTION

Overview

SPP is a perl wrapper around any of the Synopsys products that have a shell interface. This currently includes these programs:

  bc_shell
  budget_shell
  dc_shell
  dp_shell
  dt_shell
  fpga_shell
  lc_shell
  pt_shell
  ra_shell

SPP is similar in spirit but completely new from the original version of dc_perl by Steve Golson. Fundamentally, they are the same. On initialization, SPP forks and execs a dc_shell, pt_shell, etc process and communicates with it through an expect like interface. Using this interface, SPP is able to run commands and get the response completely within the perl environment. SPP has the ability to communicate with a Synopsys shell that was started in the default Dcsh mode or the newer Tcl mode.

If started in Tcl mode, additional functionality is provided by using the Synopsys::Collection module which maps the collection idiom that was introduced when Synopsys added a Tcl interface to all of its tools.

Requirements for Installation and Execution

First and foremost, SPP requires a Synopsys license. You must be able to run the desired Synopsys shell by itself or SPP just won't work. Second, SPP requires an unbundled perl module available from CPAN, IO::Tty. SPP was developed with perl5.00503, although it has been tested with perl5.00404.

SPP was developed on a Sun Solaris 2.6 workstation. It was written to work on any platform where a Synopsys shell could run but this could not be verified. The only known requirement is that the given product be in your PATH, and that your PATH contains a useable sh.

Methods

new($shell_name, [@shell_options])

Returns a new SPP object or undef on failure. $shell_name must be any one of the shell names mentioned above, that is:

  bc_shell
  budget_shell
  dc_shell
  dp_shell
  dt_shell
  fpga_shell
  lc_shell
  pt_shell
  ra_shell

@shell_options is a list of options that $shell_name takes. See the Synopsys documentation for $shell_name for a description of the available options.

One option that all Synopsys products take is -x which specifies commands to run immediately before the first prompt is printed. new() adds the command:

  set sh_enable_page_mode false; (Tcl Mode)

  enable_page_mode = false;      (Dcsh Mode)

to the -x argument. This is defensive programming. SPP is happier and more portable when native Synopsys paging is disabled. While SPP has the ability to recognize and cope with native Synopsys paging most of the time, occasional glitches are still observed with it enabled.

new() tries very hard to use the current environment to execute the proper program with the correct settings. It uses the sh script named $shell_name provided by Synopsys to extract the name of the program binary and any environment variables to set.

After forking, new() ties the child's STDOUT filehandle back to the parent but leaves STDERR alone. Observation shows that all Synopsys shells write their output only to STDOUT which means that all tool output will be captured by SPP. This allows the user to print to STDERR from within their own Tcl scripts (Dcsh mode has no concept of STDERR), giving them the option to bypass the SPP interface altogether.

Finally, new() initializes some object settings that are described below. The verbose() setting is set to whatever the $Verbose variable was set to (defaults to zero). nonblocking() is set to whatever the $Nonblocking variable was set to (defaults to 0).

verbose($verbose_level)

Sets the verbose level to $verbose_level which must be an integer, returns the old value. If called with no arguments, the current value is returned. The verbose level is initialized at object creation to whatever value was in the $Verbose variable. See the Verbose Levels section for a discussion of the meaning of the different levels that $verbose_level can be.

install_data_handler($code_ref)

Installs $code_ref as a streaming data handler. $code_ref must be a reference to a subroutine. Has no return value. Typical usage is as follows:

    $shell->install_data_handler(\&my_data_handler);

    ...
    ...

    sub my_data_handler {
      my ($shell, @data_lines) = @_;

      foreach $line (@data_lines) {
        # do something useful
        ...
        ...
      }
   }

Normally a command response is not available until the command completes. However, the data_handler will be called whenever a complete line (or more) of data has been received from the Synopsys shell. This allows streaming analysis of the response data.

reset_data_handler

Resets the data_handler. After this method is called no handler will be called back during command response. At startup, this is the default configuration.

install_error_handler($code_ref)

Installs $code_ref as the error_handler. $code_ref must be a reference to a subroutine. Has no return value. Typical usage is as follows:

    $shell->install_error_handler(\&my_error_handler);

    ...
    ...

    sub my_error_handler {
      my ($shell, $error_type) = shift;

      # Command had an error
      if( $error_type == 1 ) {
        $shell->printer(1, "Error with the command '", 
              $shell->current_command, "', exiting.\n\n",
              $shell->output_string);
        return;
       
      # System call error
      } elsif( $error_type == 0 ) {
        $shell->printer(0, "System call error. ",
                           "Stop hitting Ctrl-C!\n");
        return;

      # Synopsys shell is dead!
      } else {
        $shell->printer(0, "Fatal error, exiting.\n");
        exit;
      }
    }

Once an error_handler has been installed, it will be called if any command returns a value that indicates that the Synopsys shell has died, had a system call error or it was determined that the current command had an error. Currently, it is assumed that the current command had an error if the returned text matches the regular expression:

    /^Error: /m

The error_handler is called with two arguments. The first is the $shell object itself. The second is an integer, $error_type, that indicates what type of error occurred. A value of 1 indicates that a command error took place, a value of 0 indicates a system call error and a value of -1 indicates a fatal error.

If no error handler is installed, the following default handler will be executed:

    sub default_error_handler {
      my ($shell, $error_type) = @_;

      if( $error_type == 1 ) {
        if( $shell->verbose < 3 ) {
          $shell->printer(1, "Error with the command '", 
                             $shell->current_command, "'\n\n",
                             $shell->output_string);
        }
      } elsif( $error_type == -1 ) {
        $shell->printer(0, "Fatal error, exiting.\n");
        exit;
      }
    }

This handler will print out an informative error message for commands that had an error with the condition that they wouldn't be printed anyway (since command output is echoed starting at verbose level 3).

The handler exits on fatals, but does nothing for system call errors since they are always printed.

If you want to disable the handler altogether, do this:

    $shell->install_error_handler(sub {});

not this:

    $shell->install_error_handler(undef);

which won't work.

Finally, the error handler is not called when the Synopsys shell exited with a normal status.

nonblocking([0 | 1])

Sets the object to either be in blocking or non-blocking mode. With no arguments, the current value is returned. The nonblocking mode is initialized to whatever value was in the $Nonblocking variable when the object was created. See the Nonblocking mode section for a discussion of blocking versus nonblocking mode operation.

name()

Returns the name of the shell that was exec'ed by this object. For example, dc_shell or pt_shell.

tcl_mode()

Returns 1 when the underlying Synopsys shell is running in Tcl mode and zero when running in the default Dcsh mode.

printer($when_to_print, @what_to_print)

Prints the list specified by @what_to_print to the filehandle specified by the logoutput() when the current verbose level is greater than or equal to $when_to_print. $when_to_print is an integer in the same range as the values of verbose.

run($command, [$verbose_level], [$update])

Executes the Synopsys shell command specified by $command on the Synopsys shell. $command must be specified. run() will always add a single newline to the end of command. See the section on long commands for a discussion of the limit of the lengths of commands.

If $verbose_level is defined, the verbose level of the object is temporarily changed to this new value for this command. This allows the user to suppress the output of a command when it is part of a larger function that will output its own status.

If the $update is specified, its value will control whether or not the command output status will be updated in output_lines(), output_lastline(), and output_string(). The default is to update the object with new values for every command. Most users will not have a need for this flag.

The temporary changing of the verbose value has some additional constraints. The flag will only be changed if the current value of verbose() is less than four or if the value of $verbose_level is zero. This allows for two situations. The first inhibits the changing of the verbose() value when verbose() is set higher than 4 which is convenient when a user command might have lowered the verbose() flag but the user really wants to see the command output. The second situation is for commands that never want their output printed, independent of any setting of the verbose() flag.

If nonblocking() mode has been set, run() returns 1 immediately after the sending the command to the Synopsys shell. In this case, the verbose level is not temporarily changed. The default is blocking mode where run() will wait for the command response before returning.

The return value of run() is the same as wait_response().

Using Perl's $AUTOLOAD capability, any command can be directly called and translated into an equivalent run() invocation. The syntax is:

    $shell-><command>(@opts);

Which is translated to:

    $shell->run("<command> @opts");

For example, the following two lines are equivalent:

    $shell->read_verilog('foo.v');

    $shell->run('read_verilog foo.v');

The first method is preferred for it's readability.

current_command()

Returns the current_command. Returns undef if no commands have been executed.

exit()

Sends an exit command to the Synopsys shell. No value is returned. It is considered good programming style to exit the Synopsys shell before exiting yourself.

output_lines()

Returns a list of lines from the last executed command. Each line has had the ending newline removed.

output_string()

Returns a single long string that contains the entire output of the previously executed command. The newlines in the string are intact. This method is useful to print out the response of a command.

output_lastline()

Returns the last line of the list that would be returned by output_lines(). This method is useful if it is known that the desired return value of a command will always be contained in the last line of the output.

perl_list2tcl_list(@list)

Returns the Tcl list string representation of @list. Returns double quotes (``'') when @list is not defined or empty. Note that it literally returns two quote characters, not the empty string in this case.

In the common case, it uses the Tcl command list to create a string suitable to include a run() command. Given that @list has 4 elements equal to:

    qw(foo, bar, baz, biff)

This method will produce the following string:

    [list foo bar baz biff]

Note that a list is returned even if @list has only one element.

synopsys_list2perl_list($string)

Returns the perl list extracted from the synopsys type list. Synopsys lists have the form:

    {"foo", "bar", "baz", "biff"}

which would return the following perl list:

    qw(foo, bar, baz, biff)

An empty list is returned if $string is not defined or has zero length.

get_options($argv_ref, $config_ref, @options)

This method provides a convenient interface to extract and error check user supplied options to higher level commands. get_options() uses the Getopt::Long module to parse the arguments. $argv_ref should be a reference to a list of command line arguments supplied by the user. $config is a reference to a list of options defined by the Getopt::Long::Configure method and @options specify the linkage of the command line parameters. See the Getopt::Long documentation on how to use this method.

The return value is whatever value was returned by the call to Getopt::Long::GetOptions. $argv_ref is modified so that any parsed options are removed.

fileno()

Returns the file number of the Synopsys shell. Not normally needed.

pty()

Returns the pty object (IO::Pty) of the Synopsys shell. Not normally needed.

pid()

Returns the pid of the Synopsys shell. Not normally needed.

readable()

Returns 1 if the Synopsys shell has data available for reading. Returns 0 if a read would block and returns undef on an error. This method should only be used in nonblocking mode.

read_data()

Reads any available data from Synopsys shell. This method will block if no data is available. Use readable() to determine whether any data is ready to be read. This method is normally used only in nonblocking mode.

read_data() returns 1 when a full command has been received, 0 when data was read but only a partial response was processed and undef when it detects that the Synopsys shell has exited.

wait_response([$update])

Waits for the next command response from the Synopsys shell. Returns undef when it detects that the Synopsys shell has exited, returns 0 when it had a system error (interrupted system call). Otherwise, wait_response() returns 0 if the response text matched the following regular expression:

    /^Error: /m

and 1 if not. This error detection heuristic is believed to be correct, but it may not be.

If $update is 0, the data used by output_lines(), output_line(), and output_string() is not updated. If not supplied, or set to 1, those items are updated. Most users will have no need to use $update.

Normally, wait_response() blocks until the next command response is received. However, if read_data() has just been called and returned 1, wait_response() will not block and will process the just received text.

This method should only be used in nonblocking mode.

Interface to Synopsys::Collection

SPP provides a convenient interface to the methods provided by the Synopsys::Collection module. Note that this interface is only defined when the Synopsys shell was started in Tcl mode. The following methods can be called to create a Synopsys::Collection object:

    get_cells
    get_clocks
    get_designs
    get_lib_cells
    get_lib_pins
    get_libs
    get_nets  
    get_pins
    get_ports
    current_design

The arguments that each takes is identical to the arguments that the like Tcl functions accept.

The following methods also return a Synopsys::Collection object but they also require that their first argument be an existing collection object:

    add_collections
    compare_collections  
    copy_collection
    filter_collection
    index_collection
    remove_from_collection
    sizeof_collection
    sort_collection
    query_objects

Each of these methods, and their differences with their Tcl brethren, is fully described in the Synopsys::Collection documentation.

Interface to other Synopsys shell Commands

Using Perl's $AUTOLOAD facility, any method which isn't recognized will be assumed to be a Synopsys shell command. Any Synopsys::Collection objects will be expanded to their Tcl variable value. This will work:

    $shell->report_attribute('-application', $collection);

which will expand to the Synopsys shell command:

    report_attribute -application $_pvar3456

This will not work:

    $shell->report_attribute("-application $collection");

which will expand to the Synopsys shell command:

    report_attribute -application Synopsys::Collection=HASH(0x34e768)

It would be easy to override this facility by defining a command in the Synopsys, or Synopsys::Extras package, or specializing the AUTOLOAD subroutine.

Class Variables

Below is a description of some variables that can be read or set without first creating an object. They can be used to influence how subsequently created SPP objects are initialized. To set the default verbose level to 4, do this before new() is called:

    $Synopsys::Verbose = 4;
$VERSION

Read only. Contains the current version of SPP.

$Verbose

Used to initialize the verbose() method. See the Verbose section for discussion on the different levels of verbose. The default value of $Verbose is 0.

$Nonblocking

Used to initialize the nonblocking() method. See the nonblocking mode section for discussion of how nonblocking mode versus blocking mode operates.

%Shells

Read only. A hash that should be considered read-only. The keys of the %Shells hash contain all the supported SPP shell names.

Verbose Levels

The useful range of verbose levels is between 0 and 10 inclusive. Setting the verbose level through the verbose() gives the user control over how much information is printed during operation.

Keep in mind the difference between this method and the printer() method. The first argument to the printer() method specifies a minimum verbose level which must be present to see the given message. The higher the verbose level the more output that will be generated and the lower the value of the first argument printer() the more likely that it will be printed.

Method writers are asked to follow the conventions presented below so that users see a uniform type of output when they set the verbose level to a given value.

level 0

Very, very quiet. Only fatal errors are printed.

level 1

Quiet, only error messages are printed

level 2

User level. This level exists to allow higher level method writers a way to output their own messages while suppressing all others.

level 3

The default setting for interactive use. Commands are not echoed as they are executed, but their responses are.

level 4

Commands are echoed as they are executed. Useful for debugging higher level scripts.

level 5

Not used.

level 6

Not used.

level 7

Not used.

level 8

Turns on Pty debugging. Generates lots of output with information about the low level interaction with the Synopsys shell. Useful for debugging Pty problems.

level 9

Even more output is generated.

level 10

Still more output is generated.

Nonblocking Mode

One of the more intriguing possibilities when using SPP is to simultaneously start many Synopsys shells at the same time from within the same script and allow them to communicate with perl as the glue language. This would be especially useful when the script was run on a multi-processor machine where the operating system would handle running the different shells on different processors.

To enable nonblocking mode, either set the $Nonblocking variable before new() is called or use the nonblocking() method on the just created object.

Once in nonblocking mode, all calls to run() will return immediately and it will be the responsibility of the application to monitor the Synopsys shell to know when response text is available.

Note that the call to new() will always blocks until the Synopsys shell prints its first prompt. This is necessary to ensure proper startup. The following example shows how one would startup 4 simultaneous dc_shell sessions and monitor them:

  $Synopsys::Nonblocking = 1;

  my $fd = '';
  for($i=0 $i<4; $i++) {
    $shell[$i] =  Synopsys->new('dc_shell', @ARGV)
        or die "Init of '$shell_name' #$i failed, exiting.\n";
    vec($fd, $shell[$i]->fileno, 1) = 1;
  }

  my $tmp;
  while( 1 ) {
    # Block until something is readable
    next if select($tmp = $fd, undef, undef, undef) < 0;

    # Find out who is readable and read them
    for($i=0 $i<4; $i++) {
      if( $shell[$i]->readable ) {
        my $done = $shell[$i]->read_data;
        if( not defined($done) ) {
          warn "shell $i died! Oh no!";
        } elsif( $done == 1 ) {
          # wait_response won't block when 
          # called after read_data() returned 1
          $shell[$i]->wait_response;

          # Do shell $i specific stuff
          foreach my $line ($shell[$i]->output_lines) {
          }
        }
      }
    }
  }

Command Line Length Limits

The run() method has some fundamental limits on the length of a command that can be sent to the Synopsys shell. Through experimentation, the following has been determined.

Any command less than 1024 bytes will be processed as a single command string. The Synopsys shell will respond to these commands with one prompt.

Beyond that it seems that a Synopsys shell has a hard limit on command length of 1024 bytes. Any command longer than that is cut into 1024 byte chunks and processed as separate commands on 1024 byte boundaries. Unfortunately, this means that any command that straddles a 1024 byte boundary will be split into two strings and probably cause errors on both the preceding and succeeding command chunks.

After the 1024 byte limit has been reached, it has also be experimentally determined that any command longer than approximately 210,000 bytes will cause the pseudo-terminal driver to stop functioning altogether. This limit doesn't seem troublesome because 210,000 bytes is a lot of data and the 1024 byte limit would probably curtail most attempts at long commands.

What about embedding newlines into command strings? While this at first seems like it would be a good idea, it causes some additional problems. The first is that the send/response nature of SPP would break. Each newline would generate a prompt from the Synopsys shell which would cause SPP to assume that the current command had completed. Of course, the current command hasn't completed so the user must write a nonblocking mode solution to keep track of all the data. Additionally, all of the partial outputs of the commands will continually be overwritten everytime another prompt is received.

The bottom line is that commands over 1024 bytes and commands with embedded newlines are a bad idea. Maybe the proper solution in this case is to write the Tcl/Dcsh code to a file and send one source/include command to read it in.

TROUBLESHOOTING

Since this modules has only been tested on one platform, it is likely that it won't work correctly on others. If you cannot get SPP to initialize or if you're having any other type of problem, the best thing to do is set the verbose level to 8, save the output to a file and email it to me <jsolomon@vlsi.stanford.edu>.

SEE ALSO

Synopsys::Collection, synopsys_shell

AUTHOR

Jeff Solomon <jsolomon@vlsi.stanford.edu>

Back