Querying the Encounter database with dbGet is typically pretty concise to begin with. But you might not be aware of its support for expression-based matching, which enables even more compact scripting.
Let's take a very simple but common scripting challenge: Finding all of the high fanout nets in the design.
Then let's take this a little further. How would we write a script to find all nets with fanout greater than "n" which are not clock nets?
Historically we'd do this by iterating through all of the nets in the design, checking whether their fanout is greater than "n", checking whether it is marked as a clock net, and if so add it to a list of nets that meet the criteria. This would take about a half-dozen lines of code.
But by using dbGet's support for expression-based matching, we can make this script more compact. Here's how it works.
First, let's look at how we'd write this script without expressions:
set high_fanout_nets {}
foreach net [dbGet top.nets] {
if {[dbGet $net.numInputTerms] > 32} {
if {![dbGet $net.isClock]} {
lappend high_fanout_nets $net
}
}
}
return $high_fanout_nets
Here's how we'd write the same functionality using dbGet's expression-based matching:
encounter 1> dbGet top.nets {.numInputTerms > 32 && .isClock == 0}
Much more compact, right?
So here's how it works, step by step. The attribute ".numInputTerms" gives us, effectively, the fanout for each net. If we were to query that attribute for each net we'd get a list of numbers representing the fanout of each net in the design:
encounter 2> dbGet top.nets.numInputTerms
5 5 1 16 32 32 16 33 19 17 18 21 20 21 20 20 71 17 17 8 16 16 32 16
We more commonly use "simple" matching to find things we're looking for like object names, and testing for 1's and 0's. And we could certainly do that with the .numInputTerms attribute:
encounter 3> dbGet top.nets.numInputTerms 32
32 32 32 32 32 32 32 32
And if we wanted to get the pointers to those nets we could do it like this:
encounter 4> dbGet top.nets.numInputTerms 32 -p
0x2aaab4252f38 0x2aaab20acbe8 0x2aaab20acf30 0x2aaab215fc88 0x2aaab2160078 0x2aaab21faa00 0x2aaab21faca0 0x2aaab21fcab8
And if we wanted to get their names we could do it like this:
encounter 5> dbGet [dbGet top.nets.numInputTerms 32 -p].name
DTMF_INST/TDSP_CORE_INST/ALU_32_INST/n_3062 DTMF_INST/TDSP_CORE_INST/EXECUTE_INST/n_896 {DTMF_INST/TDSP_CORE_INST/EXECUTE_INST/nbus_426[0]} DTMF_INST/TDSP_CORE_INST/TDSP_CORE_GLUE_INST/n_1213 DTMF_INST/TDSP_CORE_INST/TDSP_CORE_GLUE_INST/n_1357 DTMF_INST/RESULTS_CONV_INST/n_2516 DTMF_INST/RESULTS_CONV_INST/n_2521 DTMF_INST/RESULTS_CONV_INST/n_2512
But if we want to get more sophisticated we can use dbGet expression matching. The first thing to notice is the unique syntax these expressions use. If we want to do the same as we did a couple examples back -- ie, get the pointers to all nets with a fanout of 32 -- here's how we do it with expression matching:
encounter 6> dbGet top.nets {.numInputTerms == 32}
0x2aaab4252f38 0x2aaab20acbe8 0x2aaab20acf30 0x2aaab215fc88 0x2aaab2160078 0x2aaab21faa00 0x2aaab21faca0 0x2aaab21fcab8
Notice that we select the attribute to match on with ".numInputTerms", then the criteria ("==" in this case), then the value. And we wrap it all in "{}". Note also that dbGet automatically returns pointers in this mode and doesn't require a "-p".
From there we can make it more complex, with a greater than rather than equal:
encounter 7> dbGet top.nets {.numInputTerms > 32}
0x2aaab3c5c928 0x2aaab3c5c9d0 0x2aaab3cf7898 0x2aaab3cf8c48 0x2aaab40e5890 0x2aaab42533d0 0x2aaab4253a60 0x2aaab44474b0 0x2aaab20ad080 0x2aaab20adc38 0x2aaab20c4180 0x2aaab20c44c8 0x2aaab21fb288 0x2aaab21fbfa8
Or combine two expressions to match the nets with fanout greater than "n" which are not marked as clock nets:
encounter 8> dbGet top.nets {.numInputTerms > 32 && .isClock == 0}
0x2aaab3c5c928 0x2aaab3c5c9d0 0x2aaab40e5890 0x2aaab42533d0 0x2aaab4253a60 0x2aaab44474b0 0x2aaab20ad080 0x2aaab20adc38 0x2aaab20c4180 0x2aaab20c44c8 0x2aaab21fb288 0x2aaab21fbfa8
If we wanted to get the names of these nets we could wrap it within another call to dbGet:
encounter 9> dbGet [dbGet top.nets {.numInputTerms > 32 && .isClock == 0}].name
test_modeI scan_enI {DTMF_INST/TDSP_CORE_INST/alu_cmd[1]} DTMF_INST/TDSP_CORE_INST/ALU_32_INST/n_1716 DTMF_INST/TDSP_CORE_INST/ALU_32_INST/n_1738 DTMF_INST/TDSP_CORE_INST/MPY_32_INST/n_268 {DTMF_INST/TDSP_CORE_INST/EXECUTE_INST/nbus_440[0]} DTMF_INST/TDSP_CORE_INST/EXECUTE_INST/n_4221 DTMF_INST/TDSP_CORE_INST/DECODE_INST/n_4475 DTMF_INST/TDSP_CORE_INST/DECODE_INST/n_181 DTMF_INST/RESULTS_CONV_INST/n_2509 DTMF_INST/RESULTS_CONV_INST/n_6011
I hope this is helpful in making your scripting within Encounter more compact. Check back next time and I'll show how to write these nets to a file, one net name per line by using redirect and a couple of tricks.
I'd love it if you subscribed to the Cadence Digital Implementation blogs for notification of new posts.
Question of the Day: Have you found cases where dbGet's expression based matching is particularly useful?
-Bob Dwyer