287 lines
13 KiB
Plaintext
287 lines
13 KiB
Plaintext
Hierarchical "extresist" notes:
|
|
------------------------------------
|
|
Project started January 28, 2026
|
|
|
|
Follow-on from code development of "extresist" to remove dependence
|
|
on ".sim" and ".node" files and instead to read only the ".ext" file
|
|
that will be annotated.
|
|
|
|
When we last left off. . .
|
|
The code works both for running the "extresist" code standalone,
|
|
and for using "extract do resistance" to run the detailed extraction
|
|
in sequence with the normal extraction.
|
|
|
|
Since "extresist" has only ever been recommended for use with flattened
|
|
layout, the differences appear minimal. However, by avoiding the
|
|
(flat) .sim file in favor of the (hierarchical) .ext file, it is now
|
|
possible in theory to run "extresist" on hierarchical layouts.
|
|
|
|
The one thing that is missing from this is the ability to find where
|
|
a wire connects to a subcell, and to mark this as a kind of terminal;
|
|
specifically, a terminal that connects to a subcell, as opposed to a
|
|
terminal that connects to a device. If the contents of subcells are
|
|
considered to be "black boxes", then each cell def should have its
|
|
own self-contained network of drivers and terminals. Drivers are
|
|
already handled as requiring being ports. That's meaningful only on
|
|
the cell top level, where something has to be marked as a point of
|
|
entry for each signal expected to drive the subcircuit. However,
|
|
within a hierarchy, all drivepoints that are parent-to-child connections
|
|
will be identified and recorded as "merge" entries in the .ext file.
|
|
Since the ".ext" files are built from bottom up, it should be possible
|
|
to get a complete list of drive points with exact locations instead of
|
|
relying on port labels as the expected point of entry.
|
|
|
|
Question: If "extresist" is done right after "extract", then won't
|
|
the parent cell not be available at the time of processing any given
|
|
cell, such that the list of node merges not be available? How to work
|
|
around that problem?
|
|
|
|
There is a point in extExtractStack() in ExtMain.c when all cells up
|
|
to the top have been processed but the substrate planes have not been
|
|
replaced. Here the "extresist" could simply operate on the same stack
|
|
as "extract", and parent cell .ext files will be available to parse
|
|
for "merge" statements for finding drive points upward in the hierarchy.
|
|
At the top level, when no parent exists, then the declared ports can be
|
|
used to determine the drive points.
|
|
|
|
This will require duplicating the code that actually runs "extresist",
|
|
because it will have to be run independently in any routine that calls
|
|
"ExtCell". This looks like two places, discounting "ExtTech" which
|
|
shouldn't need it: ExtractOneCell() and extExtractStack().
|
|
|
|
Done. Now it should be possible to read the .ext file of every parent
|
|
cell of a cell def to find all of the potential points of entry.
|
|
Dealing with those points of entry will be the hard part.
|
|
|
|
First, re-run the existing test (non-hierarchical) to make sure that
|
|
moving the point where extResisForDef() is called didn't mess up
|
|
anything. Looks good.
|
|
|
|
Next, run a test of how the existing code works given a hierarchical
|
|
layout. Example in ~/devel/magic/extresist_new/hierarchical/. Copying
|
|
layout from chipalooza_projects_2, top level cell sky130_am_ip__ldo_01v8.
|
|
|
|
First problem: Not finding the .ext files when reading for extresist.
|
|
But this literally *just* worked fine for the non-hierarchical cell.
|
|
What gives? --- "EFSearchPath" is NULL, this is not what's changed
|
|
by "extract path"? The value is in global variable ExtLocalPath.
|
|
Oh. . . So it *writes* the .res.ext file to the right place but it
|
|
doesn't *read* the .res.ext file from the right place. This also
|
|
means that the non-hierarchical test pulled the wrong .ext file and
|
|
should be done over, although eyeballing it, it looks okay.
|
|
There is a command "extFileOpen" that should be used.
|
|
Fixed, try again.
|
|
|
|
This more or less worked.
|
|
Needs to print out the name of the cell being processed.
|
|
Once cell, looks like the level shifter, had "missing terminal
|
|
connection" errors.
|
|
|
|
Might be source-drain connected? No, these are perfectly normal
|
|
transistors. . . Why this cell specifically? Happens even if
|
|
only the cell itself is being extracted (no hierarchy).
|
|
Error issued at ResRex.c:1512. layoutDev->rd_terminals has all
|
|
null contents.
|
|
Note that "rd_fet_gate/source/drain/subs" is equivalent to
|
|
"rd_terminals[0/1/2/3]" and either form might be used. The
|
|
rd_terminals[*] form seems to be used only for initialization.
|
|
Looks like ResNewSDDevice() was never run.
|
|
|
|
Would have come from walking the device on all four sides;
|
|
ResNewSDDevice would have been called from ResEachTile.
|
|
|
|
Break on ResEachTile() for the gate tile in question, which would
|
|
be at 1406, 563. Apparently that never happens?
|
|
5th call to ResProcessTiles().
|
|
|
|
Note that "Adding <node name>" only appears sometimes. When it
|
|
is omitted, resisdata->rg_bigdevres is zero. Example, VPWR?
|
|
rg_bigdevres copied from "minRes" in ResProcessNode().
|
|
"Find largest SD device connected to node" seems non-controversial
|
|
and should produce a result for node VPWR.
|
|
Break on ResProcessNode until node->name is "VPWR". Problem happens
|
|
immediately.
|
|
|
|
Ah---Caused by ptr->thisDev->resistance = 0.
|
|
This is "linear resistance" from FET line. In .sim files, this is
|
|
found in the devptr record and is relevant.
|
|
Added code to get the value of device width from the .ext file and
|
|
determine the linear resistance according to the tech file values.
|
|
(Except that the open PDKs don't have these values. . . something
|
|
to deal with later.) (Since this seems important, made it default
|
|
to 10k instead of 0.)
|
|
|
|
Oddly, these changes made exactly zero difference to the output.
|
|
"minRes" is being set to zero, perhaps for no good reason.
|
|
Now things are worse: "Adding" only shows up once, for VPB,
|
|
and now there's a new error about "VPWR" being an "orphaned node"
|
|
and being connected (arbitrarily) to "VPWR.t1". . .
|
|
Went back to setting minRes to zero for FORCE or DRIVELOC.
|
|
Anyway, this seems to have nothing to do with the missing terminal
|
|
connection and has just been a distraction.
|
|
|
|
Example where ResNewSDDevice() is being called correctly:
|
|
tile = pdiff at 686, 439
|
|
tile has clientdata with resDev = L=30, W=168 @656, 439.
|
|
Tile came from a contact point record, cp->cp_tile[0].
|
|
|
|
This does not say a whole lot about why a terminal connection
|
|
wasn't found.
|
|
|
|
Staring at it for a while, I get it now: These devices are on nets that
|
|
are split into two unconnected parts but labeled the same. So the
|
|
connectivity is tracing from one of the labels, and the other gets
|
|
unprocessed. Probably gets solved by using "extract do unique"?
|
|
Yes, it does!
|
|
|
|
Found an error in other code: "extract do unique" turned a font label
|
|
into a regular label, so it got left that way. No, this is something
|
|
else and is in the original cell. Actually, this is a strange error.
|
|
"select area labels" even when applied to the entire cell, does not
|
|
find (or does not display) VGND, LVPWR, VPWR, or VPB font labels.
|
|
All non-font labels and font labels VNB, A, and X are displayed.
|
|
This behavior is not new and I will punt on it. Have no idea what's
|
|
going on, as the graphics routines appear to be working and displaying
|
|
the font label as expected.
|
|
|
|
Anyway, with "extract do unique" and "extract do resistance", I can get
|
|
a full R-C extraction netlist from the LDO layout. That leaves a lot
|
|
to be analyzed. . .
|
|
|
|
Will need a simpler hierarchical layout example.
|
|
|
|
---------------------------------------------------------------------
|
|
For now, work on analyzing the code to understand how the points of
|
|
entry (above) and exit (below) are handled. My understanding of my
|
|
previous work (which has been a while) is that there is *no* dealing
|
|
with exit points, and entry points only consider labeled ports.
|
|
|
|
Confirm this, then strategize on how to rewrite this such that any
|
|
given cell can find its exit points by looking at its .ext file
|
|
"merge" records, and its entry points by looking at its parent's
|
|
.ext file "merge" records to itself. The full list of parent uses
|
|
can be used to find all potential points of entry (some of which
|
|
might not be used in a given instance of the cell). Overlaps must
|
|
be detected and handled.
|
|
|
|
The current process stack looks like:
|
|
|
|
ResMain.c: extExtractStack()
|
|
ResRex.c: ExtResisForDef()
|
|
ResRex.c: ResCheckExtNodes()
|
|
ResRex.c: ResProcessNode()
|
|
ResMain.c: ResExtractNet()
|
|
ResSimple.c: ResDoSimplify()
|
|
ResRex.c: ResWriteExtFile()
|
|
|
|
RexExtractNet() does the following:
|
|
|
|
(loop over devices)
|
|
resMakeDevFunc()
|
|
|
|
ResShaveContacts()
|
|
ResConnectWithSD()
|
|
ResDissolveContacts()
|
|
|
|
(loop over planes)
|
|
ResAddPlumbing()
|
|
|
|
ResMakePortBreakpoints()
|
|
ResMakeLabelBreakpoints()
|
|
ResFindNewContactTiles()
|
|
ResPreProcessDevices()
|
|
|
|
ResProcessTiles()
|
|
ResEachTile()
|
|
(Then work through ResNodeQueue stack)
|
|
|
|
The relevant parts here to what needs to be added functionally are the
|
|
two routines ResMakePortBreakpoints() and ResMakeLabelBreakpoints()
|
|
These two routines should be run *only* on the top level cell of a layout,
|
|
since there is no other information specifying what it connects to.
|
|
Otherwise, I need two new routines which effectively do the same thing:
|
|
|
|
ResMakeBreakpointsUp()
|
|
ResMakeBreakpointsDown()
|
|
|
|
I have a question as to whether these really are supposed to be
|
|
"breakpoints" or if that is an appropriate designation for a terminal.
|
|
Both routines above call ResAddBreakpointFunc() which calls NEWPORT()
|
|
(macro). This is different than a breakpoint, which has NEWBREAK,
|
|
so I should probably rename the routines above to make them correct.
|
|
Each resInfo record (attached to a tile) has a "breakList" and a
|
|
"portList". But---"resAllPortNodes()" creates a NEWBREAK for every
|
|
entry in portList, and ResMakeLabelBreakpoints() calls
|
|
ResAddBreakpointFunc(), although the latter calls NEWPORT. This seems
|
|
circular and could be a case of "I did this when I didn't know what I
|
|
was doing". "resAllPortNodes()" is called at the end of ResEachTile().
|
|
|
|
Another question: ResMakePortBreakpoints() does not check the cell def but
|
|
works from the node list created by reading the .ext file, where any node
|
|
that has a "port" entry is flagged. But all ports are labels, so wouldn't
|
|
ResMakeLabelBreakpoints() create a redundant entry?
|
|
|
|
Note check at ResProcesNode() for node->status & REDUNDANT; It is not clear
|
|
to me what REDUNDANT ought to be doing in the ResReadExt code. Possibly it
|
|
should just be eliminated, and replaced by forcing EXTRACT_DOUNIQUE. For
|
|
R-C extraction there should never be two of the same node name in different
|
|
places. "node_uq0" would be just a name, like "node.n0"; it should not
|
|
matter that the label is for a junction or a terminal.
|
|
|
|
The routines appear to assume one "drive point" and multiple "terminals".
|
|
This would be a typical digital setup. The node can have a single
|
|
"drivepoint" position. This is not particularly meaningful for analog.
|
|
|
|
Maybe it makes sense to pre-partition nets so that they all end up with
|
|
the single-driver, multiple-terminal form? The idea that a net has multiple
|
|
drivers means that there are multiple points of attachment to that net from
|
|
outside. But it may be sufficient just to arbitrarily pick one node as the
|
|
driver and declare all the rest to be terminals.
|
|
|
|
------------------------
|
|
At what point in the call stack above is it possible to know whether the
|
|
current cell def is a top level cell or not? Should be possible for
|
|
anything with "def" in its argument list.
|
|
Top level cell has def->cd_parents->cu_parent = 0?
|
|
|
|
What prevents a breakpoint from being considered dangling and getting
|
|
removed? Answer: The node is marked with RES_NODE_ORIGIN. This origin
|
|
is placed at the position of a port, and if breakpoints are added, then
|
|
only the resInfo record at the origin position keeps RES_NODE_ORIGIN,
|
|
and that keeps the record from being pruned from the node. Will likely
|
|
need a different flag, such as "RES_NODE_SINK".
|
|
|
|
Seems like this should run after basic extraction and before simplification.
|
|
If a list of parent and child connection points exists after reading the
|
|
.ext files, then the connection points can be located and the resInfo
|
|
at the connection point can be set to be a sink. That may involve adding
|
|
a junction, which might be as simple as just calling ResProcessJunction()?
|
|
Or more likely, need a new handler (in ResJunct.c) to process a sink point.
|
|
Note that "ResProcessJunction()" requires two connecting tiles, which would
|
|
not be the case with a sink.
|
|
|
|
Analyze how these junction processor routines work. The resInfo field of
|
|
"tp" is searched, but the resInfo field of "tile" gets the new breakpoint.
|
|
|
|
Need to keep in mind the difference between ResNodeList, which has entries
|
|
of type "resNode" (which is basically a sub-node), and ResOriginalNodes,
|
|
which has entries of type "ResExtNode". Particularly confusing is
|
|
ResOriginalNodes vs. ResOriginNode. . . may want to change something, like
|
|
referring to the originals as Nets?
|
|
|
|
(Cleaned up a bunch of mess in the code meanwhile.)
|
|
|
|
Added RES_NODE_SINK and handling, but nothing defines it yet. It will
|
|
prevent nodes having the flag from being merged or simplified away, like
|
|
RES_NODE_ORIGIN.
|
|
|
|
Now need a routine that reads the "merge" lines from .ext files and
|
|
creates sinks.
|
|
|
|
Currently resAllPortNodes() runs at the end of ResEachTile().
|
|
It takes the Info record attached to the tile, runs through the portList,
|
|
and adds a new breakpoint. . . to the same tile. There is no check of
|
|
whether the port intersects the tile, which is probably wrong.
|
|
|
|
Time to start working with some simple examples.
|