|
|
|
SPP (Synopsys Plus Perl) - A Perl interface to Synopsys' shells
|
|
#!/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;
|
|
|
|
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.
|
|
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.
|
|
- 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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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) {
}
}
}
}
}
|
|
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.
|
|
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>.
|
|
Synopsys::Collection, synopsys_shell
|
|
Jeff Solomon <jsolomon@vlsi.stanford.edu>
|
|
|
|