( ESNUG 315 Item 8 ) ---------------------------------------------- [3/24/99]
From: "Paul.Zimmer" <paul.zimmer@cerent.com>
Subject: OUCH! The 21 Things I Tripped Over When I Switched To PrimeTime
John,
I've been making the move from DesignTime (essentially, dc_shell) to
PrimeTime recently. I'm sure a lot of ESNUGers are/will be doing the same,
so I thought I throw out a list of "oddities" that I've tripped over.
Before I do, I want to preface this with the comment that, overall, I'm
fairly happy with PrimeTime. Tcl isn't my favorite language, and
PrimeTime does fatal occasionally, but it is much better than DesignTime.
Also, I've been impressed with the hotline team's knowledge and
responsiveness. Whoever is running the PrimeTime show over at Synopsys
seems to really care about getting it right.
I haven't run this list by Synopsys (although some of the issues have
been discussed with them), so there may well be solutions to these
problems that I haven't found. If so, I hope Synopsys will post back so
that we can all benefit!
Major Oddities
==============
1) Collections
This is by far the most confusing thing. To save memory and speed
processing (so I was told), PrimeTime returns "collection handles"
instead of normal tcl lists. These are essentially pointers to internal
data structures, although users can't really use them that way.
Anyway, when you do "get_cells *" (equivalent of find(cell)), it
returns something that looks like "_sel001". It won't do any
good to echo $_sel001. If you want to see what is in _sel001,
there are two ways:
1) If you're doing this interactively, just use "query" (short for
query_collection) where you would have used "list" in dc_shell.
You can't, however, access $_sel001 directly.
# this doesn't work:
pt_shell> get_cells *
_sel1
pt_shell> echo $_sel1
Error: can't read "_sel1": no such variable
# these work
query [get_cells *]
or
set _cells [get_cells *]
query $_cells < works
2) If you want to echo what's in the collection (often just one
thing), use get_attribute ... full_name:
foreach_in_collection _thingie [get_cells *] {
echo [get_attribute $_thingie full_name]
}
This get_attribute ... full_name happens so often that I wrote a
procedure to do it:
proc fullname thingie {get_attribute $thingie full_name }
One annoyance I haven't found a good way around is adding up multiple
collections. There is a command "add_to_collection", but it only
allows ONE collection to be added. When you're trying to do stuff
like adding collections of D pins that match half a dozen different
names, this gets very clumsy.
The other one that always bites me is remembering to use
"foreach_in_collection" instead of "foreach". You have to get used to
thinking about this every time you write a loop.
3) PrimeTime, like DesignTime, still doesn't support output clocks in
any reasonable way. That's a pity, because almost every chip these
days uses them. I'm talking about interfaces where you source both
the clock and the data. A clock comes in (or is generated internally),
and is used to clock output flops, then is sent out along with the data.
This is a virtual requirement for any high-speed interface.
Anyway, what the designer wants to do is just declare the output clock
pin as a generated clock, and declare the input/output delays as
relative to this clock - straight from the data sheet.
Unfortunately, you can't do this. Instead, you have to somehow time
the path from the original source clock to the output clock pin, then
adjust the input/output delays be this amount. With DesignTime, this
meant doing a "report_timing" out to a file, then sed/awk/grep'ing
the result back in. PrimeTime can do this with "get_timing_paths".
But still, this is tricky enough to get right in the simple case with
no inverted clocks, but when you start inverting the clocks, things
get REALLY interesting. And it is all so unnecessary. PrimeTime has
all the information, it just needs to know how to use it. And,
again, this is SO common. PrimeTime is almost there. It will let
you create a generated clock with a divide_by 1, but it doesn't time
the paths quite correctly. I hope they fix this soon.
4) all_clocks
all_clocks (synonym for get_clocks *) returns some of the clocks all of
the time, and all of the clocks some of the time, but doesn't return all
the clocks all the time.
Basically, generated clocks are NOT returned in all_clocks until AFTER
you've done a "check_timing" (or had it done implicitly by issuing
a report_timing or similar command).
This is unfortunate if you're trying to use all_clocks to set false
paths between the clocks BEFORE doing check_timing (since check_timing
will take forever if you have async clocks and haven't set false paths
between them). The workaround is to create your own version:
set _all_clks [add_to_collection [get_clocks *] [get_generated_clocks *]]
Unfortunately, this will create duplicates if check_timing has already
been run... I think there's a PrimeTime command for getting rid of
duplicates in a collection, but I haven't tried it.
Anyway, I think it's a bug. all_clocks should return the same thing
before and after check_timing.
5) Clock gating checks don't respect set_case_analysis.
The chip operating mode that you have defined using set_case_analysis
doesn't propagate for clock gating checks.
This basically makes clock gating checks useless as far as I'm concerned.
I have discussed this with Synopsys. I get the impression that they
intend to fix this in the future.
6) Can't easily save results
This is a pity. You run a script that sets all sorts of constraints
and timing exceptions, and you can't save away the result for quick
loading later (or as a backup in case of a crash). Fortunately
PrimeTime is fairly fast, but it still would be handy to be able
to write out a ".ptdb" file. My entire top-level constraint script
takes over 1.5 hours to run on a 300MHz Sparc - so waiting to load
it up to look at some detail interactively is a real pain.
Nits
====
1) No "source" attribute on GENERATED clocks. Very strange. Normal clocks
have an attribute called "source", but not generated clocks. Furthermore,
PrimeTime won't even let you create a user attribute on a generated clock
object, so you can't even do it yourself when you create it. This is
a pity, because (in scripts) you often want to know the source for
a generated clock. I do it by keeping an array called "gen2src" that I
build as I declare the clocks.
2) Annoying errors:
PrimeTime issues errors for things that aren't that serious, and I can't
find a workaround for some of them. This is a problem, because my
checking scripts don't expect the string "Error:" to be OK!
Strange things that generate errors:
-----------------------------------
1) Accessing a variable that isn't set.
(You can work around this by doing:
if {info exists foo} {...
2) Accessing an ARRAY variable that isn't set.
(I haven't found away around this, because "info exists" doesn't
seem to work on arrays.)
3) Using a get_.. command that SHOULD just return an empty collection:
pt_shell> query [get_ports pllmn/ICLK]
Warning: No ports matched 'pllmn/ICLK' (SEL-004)
Error: Nothing matched for ports (SEL-005)
pt_shell>
There IS a way around this one. Use the "-quiet" switch on get_...
3) Tendency to crash, esp. if you re-define clocks
I do see more crashes with PrimeTime than I saw with DesignTime.
This said, I have yet to see a crash when I'm running in batch mode.
It's when I screwing around interactively with pt_shell, especially
when I'm re-defining clocks, that I get crashes.
Don't get me wrong. Overall, PrimeTime is reasonably stable. But
it could be better :-).
5) PrimeTime shares one really annoying habit with DesignTime - it isn't
too clever about strings vs objects (collections). For example,
when a command has an option "-clock clock", I should be able to
say "-clock $foo", and it shouldn't matter whether $foo is a string
name of the clock, or the clock object. Too many commands insist
on the string version. This is easier with PrimeTime using the
full_name attribute than with DesignTime, but it is still an irritation.
Tips
====
1) Arrays and Quotes
The statements:
set foo(bar) 1
set foo("bar") 1
create TWO DIFFERENT elements in array foo - one named 'bar' and one
named '"bar"'!
If you're coming from a perl background, that foo(bar) thing looks
funny - but get used to it!
2) Creating an empty collection. I didn't expect it to be so simple.
You just do "set foo {}".
3) PrimeTime's report_timing command has a really neat switch called
"-path_type full_clock". This will cause the timing report to show
you both clock paths right in the report - very handy for examining
hold time failures.
4) Get to know "get_timing_paths". This is the mechanism that allows you
to parse timing paths without resorting to doing report_timing to
a file and using unix commands to hack it up. It is really quite handy.
5) In Tcl, variables used in a process (subroutine) are local by default.
So, you have to say "global foo" to get access to foo. This one
bites me all the time.
6) Using the -regexp switch. Put the whole argument in curly braces:
[get_cell -hier {.*} -regexp \
-filter {full_name =~ .*LOCKUP && ref_name =~ ld.*}]
BTW, this points out another feature of Primetime. The -hier switch
is actually useful. You can do things -hier from the top of the chip
and get a result back in a reasonable amount of time!
7) PrimeTime has a nifty new help command that accepts (dumb) wildcards,
so you can do "help *coll*" and see all the collectin commands.
Very nice.
That's all for now. Sorry this got so long, John, but I thought it might be
useful to other people learning PrimeTime.
- Paul Zimmer
Cerent Corporation
|
|