Additional changes; fixed some of the most problematic issues

involving searches on split tile areas, including one very
important check for interaction between split tiles during
hierarchical extraction.  There is still something wrong in
the hierarchical extraction, but it could be the last remaining
issue.
This commit is contained in:
R. Timothy Edwards 2026-01-15 21:35:46 -05:00
parent 8bd01f5597
commit 846c8e0f65
15 changed files with 1841 additions and 253 deletions

988
README
View File

@ -467,3 +467,991 @@ Whew. Is that all? (Almost certainly not.) Yes, missed code at ExtBasic.c:520
and below. (fixed)
Okay, it compiles again! Time to test again!
Testing from ~/projects/efabless/sky130_lvs/ script "./run_pad_lvs_2.sh extract".
Possibly magic crashed while doing the extraction. . . ?
Eww, died at "extract unique notopports".
ExtRegion.c:304. reg = NULL.
Tile type locali in "sky130_fd_io__res75only_small", ended up with NULL ClientData;
this isn't supposed to happen, is it?
Seems like extHasRegion() failed. Ah, no, it's defined so that only CLIENTDEFAULT
is considered "not a region". But I changed stuff around that. . . so. . .
ExtSetRegion() never passed reg = 0, so it ended up as 0 some other way.
Ah, this is the definition of VISITPENDING, so all tiles get ci_client = 0 on
PUSHTILE.
Conclusion: "ExtGetRegion(tile, dinfo) == arg->fra_region" failed for some reason.
arg->fra_region is non-NULL, and ExtGetRegion returned 0, so this check should have
failed. Failed at ExtNghbors.c:120.
Ah---there's an improper semicolon there!
But, still died. But it's further along. Died where it tried to access the split
region structure. "tp" is definitely the known split tile with two regions.
ExtGetRegion() has been called before a region has been assigned. Forgot to handle
this case.
Now deeper. . . Split tile handling is more or less correct but ExtFindRegions()
never visited the gate side of the tile, and so its region was still set as 0
("VISITPENDING"), meaning that it was reached but somehow didn't get handled by
POPTILE.
Looking only at cell sky130_fd_io__signal_5_sym_hv_local_5term:
Breaking on "extTransFirst"---This is a double-node tile. The region's tile and
type is set to this tile, but the region isn't attached to the tile here.
extTransFirst sets right region of tile at 695, 1712.
extTransEach (called from ExtFindNeighbors) calls extSetNodeNum() on the same tile,
same side.
Next tile is regular transistor non-split tile at 735, 672
Breaking on ExtSetRegion():
(1) Tile at 695, 1712 sets right region. Left type remains unvisited. (Okay)
(2) Tile at 735, 672 sets only region
(3) Tile at 855, 672 sets left region. (okay)
(4) Tile at 855, 1712 sets left region. (okay)
(5) Tile at 695, 672 sets right region. (okay)
(then there is an unrelated rmetal1 device)
This all looks right. . . so what happened?
The tile at 695, 672 is left in transList (first entry, end of linked list)
In loop at ExtBasic.c:2189, "reg" is set to this region pointer.
But it still seems to be failing at ExtBasic.c:2227. This should not return 0!
So now the tile at 695, 1712 has a left region set but not a right region!
I think that the code wrote over the original and created a new ExtSplitRegion. . .
Look at ExtSetRegion whenever the tile is the one at 695, 1712. It should be
visited twice.
2nd time visited: Okay, this is the drain side. (region is poly tile at 655, 558).
Except---A poly tile should be part of the gate node?? Assume not, for now. Check
afterward.
Houston, we have a problem. The client for this tile was reset to 0. Run again and
check the client value for changes.
Reset happened in DBResetTilePlaneSpecial().
From: ExtResetTiles() in ExtRegion.c:529
From: extBasic() at ExtBasic.c:236
So problem is: extFindNodes() at ExtBasic.c:279 should have marked the tile again,
but didn't. See extNodeAreaFunc(). Break here on the same tile as above (at 695, 1712).
It never got there?
Never called extNodeAreaFunc() at all. I have done something improper with CLIENTDEFAULT
there. . . ?
Found a tile in which ti_client was still set to a region, so ExtResetTiles() failed
to reset all tiles. . . ?
Check what DBResetTilePlaneSpecial does; on plane 10, I'm seeing the tile at (121, 2271),
which is the first non-space tile in the search, not having been reset.
(break from ExtRegion.c:529).
Argh, that doesn't match what I saw before!
Start over. . .
Try again with the tile at (695, 1712). Find it when it is first encountered at
ExtSetRegion and track its changes thereafter.
(1) break ExtSetRegion if tile->ti_ll.p_x == 695 && tile->ti_ll.p_y == 1712
(2) print &tile->ti_client
(3) watch *(this value)
Result: 1. ExtBasic.c:4496, sets the client pointer to an ExtSplitRegion.
2. DBResetTilePlaneSpecial() sets it back to CLIENTDEFAULT.
3. extNodeAreaFunc() sets it to VISITPENDING
4. ExtResetRegion() sets it back to CLIENTDEFAULT
From ExtBasic.c:5280
Don't understand the use of ExtResetRegion() here. The "Count split tile twice"
comment comes from old code. It should not do that, right?
This code needs to go. See the similar code in ExtFindRegions which was already
fixed correctly.
Back to running run_pad_lvs_2.sh. . .
But do the full pad extraction manually first.
Oops.
Crashed.
Looks like this one died on sky130_fd_io__gpiov2_buf_localesd.
That has two of the flanged gate transistors, in a different orientation.
Problem freeing in DBResetTilePlaneSpecial(). But need to recompile with the
correct malloc. . .
And may need to go back to valgrind.
DBResetTilePlaneSpecial() tried to free ti_client which was set to CLIENTDEFAULT.
May be a trivial error.
Lookin' good!
(Note: When running run_pad_lvs_2.sh directly, reading the GDS takes a long time
because it is reading cells out of order and having to continuously recycle the
entire file. Do not be alarmed, but it should be investigated.)
Darn. Although it worked on the magic database, it crashed on the GDS database.
Not done yet!
Will probably need valgrind for this one.
Running ExtFreeLabRegions() on the node region list passed back from extBasic()
but somewhere it ended up on a bogus entry.
According to valgrind, there was an entry in nodeList that was also in transList.
The transList is cleaned up by extBasic(), then magic crashes when extCellFile()
cleans up nodeList and tries to free the same entry.
Block allocated at extTransFirst()---> TransRegion.
Then freed by ExtFreeLabRegions() at end of extBasic().
Suspiciously, this is in cell sky130_fd_io__signal_5_sym_hv_local_5term which
means that it is almost certainly due to the split tile region code.
With a diagnostic check, confirmed that there is an entry that is in both
transList and nodeList. Need another diagnostic check to figure out how that
happened. Some part of the code must be confusing the two lists?
Assume this doesn't happen during "extFindNodes". In that case,
ExtLabelRegions() has editable access to the nodeList. . .
Pinned it down to extOutputDevices(). . .
Number of node regions was axed from 9 to 6 by ExtFindNeighbors() called from
ExtBasic.c:2283. It has access to the node list in extTransRec, but it should
not mess with the node list. . .
At least now can check only nodeList and watch for truncation.
Finally pinned it down to ExtSetRegion().
Suggests that maybe ExtBasic.c:4543 ran but csr was *not* an ExtSplitRegion
and something gets overwritten. . .
Yes, exactly. If the clientdata is a node region, then expecting it to be a split
region and setting "reg_left" will overwrite "nreg_next" and mess up the node
list.
Break instead on ExtBasic.c:4534. It's possible that the tile region is being
set by something other than ExtSetRegion. . .
(1) tile at 855, 1712: client is 0.
(2) tile at 855, 672: client is 0.
(3) tile at 695, 672: client is 0.
(4) tile at 695, 1712: client is 0. (1-4 is unrelated def)
...
(5) tile at 695, 1712: client is 0.
(6) tile at 855, 672: client is 0.
(7) tile at 855, 1712: client is 0.
(8) tile at 695, 672: client is 0.
(9) tile at 855, 1712: client is 0.
(10) tile at 855, 672: client is 0. <--- Stop here and watch the ti_client space.
(11) tile at 695, 672: client is 0.
(12) tile at 695, 1712: client is 0. (all happened before diagnostic checks)
(13) tile at 695, 1712: client is 0.
(14) tile at 855, 672: client is non-zero, points to a node region.
This is not what sets the region, but PUSHTILE and variants are setting the
client regardless of the split status.
DBconnect.c:533 also sets ti_client directly.
DBconnect.c:519 also sets ti_client directly, to csa->csa_clientDefault.
The call to DBSrConnectOnePlane() at ExtBasic.c:2140 may be very problematic. . .
For now, changing PUSHTILE and its variants to use ExtSetRegion(), and
adding a guard band to the split region structure to catch immediately if
a region pointer is mistaken for a split region structure.
Lost some text during a power outage, not sure why; thought I had saved all
that. Anyway, the current plan is to create extEnumTerminal to replace
DBSrConnectOnePlane and to use a linked list instead of depending on the
tile ClientData, which is being modified by the outer loop.
After which DBSrConnectOnePlane can be removed, as it is not used elsewhere.
Also: extTermAPFunc() also needs to replace ti_client checks with ExtGetRegion().
All done! Time to check!
Ah, well, crash and burn, time for debugging.
Looks like a problem with boundary types.
Boundary inside type is tile at 855, 672, dir=1 left type 29, right type 46
With dir=1, the top and right sides are the same (46) and the bottom and left
sides are the same (29). "29" is the transistor type.
Boundary direction is 2 = BD_TOP, meaning that the "inside" tile is below the
boundary. This is wrong, because as noted above, the top of the tile, which
is the side facing the boundary, is not the transistor type.
Directions get set wrong somewhere. Good news is that the error is happening
on a split tile with neither side being space, so this is at least broken new
code, not broken old code.
Well, it's improper old code. extEnumTilePerim() does not skip sides of
split tiles as it should. It "calls the function on the perimeter tiles
as if the whole tile is the transistor type". Fixing this is likely to
result in having to handle non-Manhattan geometry in the routine that
determines device width and length.
"sides" is already set to the two sides of a split tile that need to be
ignored. for this case, tpIn is on the bottom of the boundary, dir=1,
and dinfo=0, so top and right should be ignored. But "sides" is 9, which
is BD_LEFT (1) + BD_BOTTOM (8), so "sides" is marking the sides to be
handled, not the sides to be ignored. (Fixed)
Okay, both issues fixed but don't know what that does to W, L calculations.
To be determined! I have thought about this before, though, and think that
non-Manhattan edges can just be added together (subtract edges in opposite
directions) and divide by 2; need to work out some examples on paper.
Well, that at least extracted the gpiov2 I/O cell without crashing.
Produced a lot of "Warning: Device has more terminals than defined for
type" messages which will need to be investigated. These appear to be
related to resistor extraction and don't seem to involve non-Manhattan
geometry. There are a lot of feedback entries of the type "Cannot find
the name of this node (probable extractor error)".
So the width of the non-manhattan transistor is way off (0.66um, not
5.4um or something close to it). Also the drain terminal node of the
device got lost and was output as "(none)". However, basically every
transistor drain node was output as "(none)" so it's apparently not
related to non-Manhattan geometry. Except that a handful of cells have
drain nodes listed. Don't yet know what the difference is. The "(none)"
drain node is in the .ext file. It has area/perimeter values. Given
the amount of non-Manhattan wiring in these cells, I would hazard a guess
that the problem is deriving node names from regions whose lower corner
is a non-Manhattan tile. Previously if the lower corner fell on a non-
Manhattan tile, it was moved. Perhaps the node name mechanism can be
revised, but I think using the lower left corner position for the node
name should be consistent even if the layer type isn't at the coordinate.
Debugging:
"(none)" names:
extTransOutTerminal passed NULL for lreg.
extTransRec: tr_termnode indexes are off; there are entries at 0 and 2 but
not at 1. How did the indexes get off? It all happens within extOutputDevices().
Index is "termcount".
On any cell that is generating "none" nodes, break on the next device, at
ExtBasic.c:2192.
Uh. . . Problem is that ti_client on a source/drain node tile was set to zero. . .
Note this is the value of VISITPENDING. Tile is mvndiff at 5130, -790
in CellDef "sky130_fd_io__gpiov2_in_buf".
Gate tile is simple "mvnmos" at 5141, -802.
LB(tile) = poly at 5141, -834 (but check why client is not the same as the gate?)
BL(tile) = mvndiff at 5085, -802
TR(tile) = mvndiff at 5241, -280
RT(tile) = poly at 5141, -202
Okay, but there's no null region here. . .
The boundary is at (5141, -790) to (5141, -756)
Yeah, okay, the S/D region tiles are broken up by contacts.
The full gate is (5141, -802) to (5241, -202), so the boundary is partway up the
left side of the gate.
Walk up the gate left side by looking at BL(tile) then looking at RT():
(5085, -802), (5130, -790), (5085, -756), ...
*only* the tile at (5130, -790) has clientdata 0.
How did a tile get left with VISITPENDING set and not get visited?
Something went wrong with the basic PUSHTILE/POPTILE. But I'm guessing
that my new code is at fault. . .
Okay, I think it's fixed now.
Extracted the subcell properly.
New problem now: Goes into an infinite loop on on of the cells in
sky130_fd_io__top_gpiov2. Unsurprisingly in extEnumTerminal.
Cell is "sky130_fd_io__gpiov2_ctl_lsbank"
Device is rmetal2 at 15028, 104.
Tile passed to extEnumTerminal is metal2 at 15029, 103.
The problem may persist; the tile passed to extEnumTerminal() has ti_client = 0
Oops again.
Getting better. Still have an issue with node names that cannot be found.
These appear in various places in the .ext file, but always a "cap" or "merge"
line and appear to indicate a problem finding a node in a subcell.
Start with a small cell: "sky130_fd_io__com_ctl_hldv2".
Note that the feedback for these errors is always on a split tile.
Failing at ExtSubtree.c:1141
Break on ExtSubtree.c:1127. Error occurs first time.
"tp" has dir=0, type metal1 on the right side. dinfo indicates right side.
The region is set to CLIENTDEFAULT, which is the problem: The tile was not
given a region.
Tile at 4082, 2553. Everything around it also has CLIENTDEFAULT. This is
from the cumulative extraction. . .
Going into extHierConnectFunc1, sourceDef is __EXTTREE1__ and appears to be
properly tagged with regions. Then it searches in __ext_cumulative which
appears not to be tagged with regions.
extHierConnectFunc2: Overlap area is (4082, 2553) to (4118, 2553)
Abuts but does not overlap, which is correct.
extConnectsTo() is TRUE, so it gets "name1" from extSubtreeTileToNode().
(doHard = TRUE).
I think that no region on this tile simply means that there wasn't a label
on the node.
Try breaking on ExtSubtree.c:1085 if tp->ti_ll.p_x == 4082 && tp->ti_ll.p_y == 2553.
Ahh, missed fixing a call to DBSrPaintNMArea. . . That would do it. . .
Hey, victory!
Now try LVS. . .
top_gpiov2: fails but with relatively few errors (3 m1 resistors, a handful of nets).
Not analyzed yet.
top_power_hvc_wpadv2: Passes LVS (yay!)
top_gpiov2 ESD nfet now shows W=5u in layout extraction. That is a result of
the non-Manhattan tiles being ignored for width calculations. Need to see
what the length and width calculation routine is doing, and how the non-
Manhattan edges can be incorporated. Also check some annular FETs with corner
bevels, including ones with both inside and outside bevels.
Good test: Run LVS on the GF SRAM test chip top level again.
Got some "no such node" errors on ext2spice, most related to VSUBS. Those errors
were not there before. Occurs on a handful of SRAM core cell pairs in the 1k block.
Predictably, LVS on the top level fails due to a section of unconnected substrate
in the 1k SRAM block. However, there may be more going on because the VSS and
DVSS nets are shorted in the layout netlist.
-------------The next 350 lines are basically a digression to fix an
error that has nothing to do with the new code.
The VSS/DVSS mismatch comes from the corner cell. A similar (the same?) error
was fixed recently. Re-running the I/O library validation script. Note:
Probably the same error. My commit message says that "it is still not clear
what the problem is". A workaround of collapsing an unnecessary level of
hierarchy in the cell made the problem go away. Apparently, reworking the
magic code has brought it back again. Ugh. The weird thing about this error
is that GF_NI_COR_BASE appears to be correct and has independent VSS and DVSS
nodes, but the top level shorts them; and the only thing in the top level is
the GF_NI_COR_BASE subcell and a bunch of metal5 pins! Oh, wait, there is a
cell POWER_RAIL_COR. And POWER_RAIL_COR_1 has the substrate contacts but no
isosub; could be an issue. POWER_RAIL_COR_0 merges substrate contacts to
VSUBS. POWER_RAIL_COR keeps VSUBS as a separate node. VSUBS appears to be
kept separate throughout and does not actually appear to be involved in the
error as far as I can tell.
merge links (not necessarily direct connections):
"POWER_RAIL_COR_0/VSS"
"GF_NI_COR_BASE_0/power_via_cor_5_0/m2_6384_44992#"
"GF_NI_COR_BASE_0/power_via_cor_5_0/m2_6358_25638#"
"GF_NI_COR_BASE_0/moscap_routing_0/m1_9473_n8392#"
"POWER_RAIL_COR_0/POWER_RAIL_COR_0_0/POWER_RAIL_COR_1_0/DVSS"
Suspiciously, there is feedback left saying that VSS is connected to more
than one unconnected node. Try "extract unique"? Is this just a very
hard-to-see labeling issue? Okay, with "extract unique" I see three lines
merging "VSS" with "DVSS"! All in the top level. . .
But this one?: merge "DVSS_uq0" "POWER_RAIL_COR_0/VSS_uq0"
In POWER_RAIL_COR_0, that's the 4th rail from the inside.
There is no way to determine from the "merge" lines of the .ext file where
the short happened. (ha_connHash) in ExtHier.c or ExtSubtree.c
extHierConnections()
Check at:
ExtHier.c:213
ExtHier.c:428
ExtHier.c:533
ExtHier.c:643
For when one node belongs to VSS and the other to DVSS, at the top level.
Did a special debugging string check
First failed at the third set:
node1 (length 3) is POWER_RAIL_COR_0/DVSS
next name: GF_NI_COR_BASE_0/moscap_routing_0/m1_9481_n11541#
next name: DVSS
node2 (length 55) is POWER_RAIL_COR_0/VSS
next name: GF_NI_COR_BASE_0/comp018green_esd_clamp_v5p0_2_0/top_route_1_0/m1_0_106#
next name: GF_NI_COR_BASE_0/power_via_cor_5_0/m2_2497_25638#
ha->hierOneTile vs. cum
ha->hierOneTile at (69990, 58532) type metal3
cum at (70059, 58543) type via2
-------------
2nd failure seems to be directly downstream of the first and is not worth
investigating.
1st failure, node2 is already conflating the two nodes, so get a list of all
the node names and try to pare it down further. Will take some work.
Here are the 55 names. There is not necessarily any order to these.
The string "DVSS" occurs only once in this list, and "VSS" only twice.
POWER_RAIL_COR_0/VSS (VSS)
GF_NI_COR_BASE_0/comp018green_esd_clamp_v5p0_2_0/top_route_1_0/m1_0_106# (DVSS)
GF_NI_COR_BASE_0/power_via_cor_5_0/m2_2497_25638# (DVSS)
GF_NI_COR_BASE_0/power_via_cor_5_0/m2_2497_11238# (DVSS)
GF_NI_COR_BASE_0/power_via_cor_5_0/m2_2497_6432# (DVSS)
GF_NI_COR_BASE_0/power_via_cor_5_0/m2_2497_3232# (DVSS)
GF_NI_COR_BASE_0/power_via_cor_5_0/m2_2497_32# (DVSS)
w_14068_57561# (DVSS)
POWER_RAIL_COR_0/POWER_RAIL_COR_0_0/VSS (VSS)
GF_NI_COR_BASE_0/power_via_cor_3_0/m2_2517_37527# (VSS)
VSS (VSS)
GF_NI_COR_BASE_0/power_via_cor_3_0/m2_12842_35238# (VSS)
GF_NI_COR_BASE_0/power_via_cor_3_0/m2_8741_35238# (VSS)
GF_NI_COR_BASE_0/comp018green_esd_clamp_v5p0_1_0/comp018green_esd_rc_v5p0_1_0/VMINUS (VSS)
GF_NI_COR_BASE_0/power_via_cor_3_0/m2_6358_35238# (VSS)
GF_NI_COR_BASE_0/moscap_corner_3/VMINUS (DVSS)
GF_NI_COR_BASE_0/power_via_cor_3_0/m1_14757_35210# (VSS)
GF_NI_COR_BASE_0/moscap_corner_5/VMINUS (DVSS)
GF_NI_COR_BASE_0/moscap_corner_6/VMINUS (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/m1_n33412_n19921# (DVSS)
GF_NI_COR_BASE_0/moscap_corner_2/VMINUS (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/m1_n39839_n19921# (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/m1_n43259_n19921# (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/a_n47022_n23957# (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/m1_n27687_n31792# (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/m1_n32571_n31792# (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/m1_n30132_n33522# (DVSS)
GF_NI_COR_BASE_0/moscap_corner_4/VMINUS (DVSS)
GF_NI_COR_BASE_0/moscap_corner_2_0/VMINUS (DVSS)
GF_NI_COR_BASE_0/moscap_corner_1/VMINUS (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/a_n40901_n30121# (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/a_n36513_n34394# (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/m1_n22219_n36968# (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/m1_n27687_n36968# (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/a_n34409_n36435# (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/m1_n24920_n39073# (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/a_n30340_n40567# (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/m1_n14699_n44488# (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/m1_n20058_n44488# (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/a_n28236_n42608# (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/m1_n17620_n45972# (DVSS)
POWER_RAIL_COR_0/POWER_RAIL_COR_0_0/DVSS (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/m1_n11382_n46725# (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/m1_n17715_n46725# (DVSS)
GF_NI_COR_BASE_0/moscap_corner_3_0/VMINUS (DVSS)
(on active plane offsides, this is the VSS border substrate tap)
* POWER_RAIL_COR_0/POWER_RAIL_COR_0_0/POWER_RAIL_COR_1_0/a_13097_44708# (VSS)
(next two: revised, these are treated as DVSS)
** GF_NI_COR_BASE_0/dw_13436_13361# (DVSS)
** w_13448_13361# (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/m1_n11878_n47667# (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/a_n24191_n46716# (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/m1_n14844_n49493# (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/m1_n7016_n51467# (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/m1_n9452_n51467# (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/m1_n11878_n51467# (DVSS)
GF_NI_COR_BASE_0/moscap_routing_0/a_n20244_n50771# (DVSS)
* out in space below the cell's diagonal edge
** far out in space below the cell's diagonal edge.
Now figure out how many times we land on a node merge that any name
from the list above show up, and then track that linked list until
the wrong side gets added.
1st node to show up is "w_13448_13361#", the one that is way offsides.
Connects to GF_NI_COR_BASE_0/dw_13436_13361#, the other way offsides one.
Next to show up is the last of the offsides nodes. But still VSS.
Need to break when node1 != node2.
Next is GF_NI_COR_BASE_0/moscap_routing_0/a_n20244_n50771# and
POWER_RAIL_COR_0/POWER_RAIL_COR_0_0/DVSS.
Okay, caught it at the third spot again:
name1 is w_13448_13361# (the way offsides one) (VSS)
name2 is GF_NI_COR_BASE_0/moscap_corner_3_0/VMINUS (DVSS)
Why were these merged?
cum: Type "pwell" at (39696, 21496)
ha->hierOneTile type "isosubstrate" at (39696, 21496)
Gotta think about this one. . .
Okay. Substrate generation for extraction caused this. The substrate
generation must not be honoring split tiles. The isosub tile that follows
the angled corner of the cell has been placed over the entire area of
the tile, where it then overlaps the VSS area and shorts.
But I don't see that obviously. Check dbEraseNonSub().
Not there, but did find a place where split tiles were not handled.
But fixing that didn't fix the problem. Will need to track down that
hierOneTile "isosub" type (type 10)
If breaking at extHierConnectFunc1() when oneTile has type 10, first
occurrence is x = 43896, 14405 (should probably look for split tiles,
too, although the problem above appeared to be on a non-split tile).
(43896, 14405) to (45298, 14498). The tile below it is split
(at 43896, 13361 to 44940, 14405). Check this? (okay; see below)
Then, tried breaking when oneTile is at (39696, 21496)
oneTile comes from sourceDef which is __EXTTREE1__.
sourceDef = oneFlat's CellDef.
No clue. Break to figure out where these tiles were located.
(43896, 14405) is fine and located inside the isosub area.
(39696 21496) is also fine.
The tile that generated the node way out in the middle of nowhere
that was supposedly an isosub tile was at (13436 13361). This tile
would only be found in GF_NI_COR_BASE and would be a split tile.
The node position by name would be the corner outside the isosub
area. As a *node name*, since it is the lowest plane, it would
refer to any node connected to the area.
Another thought to pursue: moscap_corner_3_0 and moscap_corner_2_0
both have bounding boxes that extend over the isosub region.
I may be barking up the wrong tree here. The node name
"GF_NI_COR_BASE_0/dw_13436_13361#" is probably correctly DVSS, not VSS,
because it represents the isosub split tile.
"w_13448_13361#", however, should be a pwell tile that was drawn for
the generated substrate, and should be VSS. But the two nodes being
merged are both DVSS. One of them got the wrong name. So go back to
where the merge occurred and find how the name was generated.
Breaking again at ExtHier.c:522 when cum location is (39696, 21496)
Breaking before the call to find the name, since it's the name that
doesn't match the node somehow.
ha->has_nodename is extSubtreeTileToNode().
First break is in POWER_RAIL_COR_0. Not what I'm looking for. Returns DVSS.
Second break is POWER_RAIL_COR, also not what I'm looking for. Also returns DVSS.
Third break is top level. "cum" has ti_client CLIENTDEFAULT.
In ExtSubtree.c:1085. r = (39696, 21496) to (41098, 22898).
type of tile is pwell. There is no pwell drawn in the cell, so pwell has
been created by the substrate generation routine.
et->et_lookNames is the top level cell.
extConnFindFunc() lands on tile at (13448, 13361). Split tile, area
(13448, 13361) -> (44940, 44853)
direction = 1, pwell on right side
dinfo is the right side, so this checks out.
Bottom line is that "w_13448_13361#" is the expected node name for this
tile and represents DVSS. It does, however, point to an issue
(unrelated to this example) that a tile with two different types
neither of which is TT_SPACE would produce the same default node
name for both of them, so the default node name generator needs
to account for the side of a split tile in the name, with an
extra character. Presumably not the problem here, though.
Moving along, then:
First encountered VSS at
name1 = GF_NI_COR_BASE_0/power_via_cor_3_0/m2_6358_35238#
name2 = POWER_RAIL_COR_0/POWER_RAIL_COR_0_0/VSS
Of interest:
name1 = GF_NI_COR_BASE_0/dw_13436_13361#
name2 = w_14068_57561# (not seen before, but clearly inside DVSS)
Note: power_via_cor_5_0 is the one inside the DVSS domain.
comp018green_esd_clamp_v5p0_2_0 is the DVSS domain clamp under it.
name1 = POWER_RAIL_COR_0/POWER_RAIL_COR_0_0/VSS
name2 = GF_NI_COR_BASE_0/power_via_cor_3_0/m2_12842_49632# not in list above?
(but it is VSS, so it's correct)
(??)
name1 = GF_NI_COR_BASE_0/power_via_cor_5_0/m1_14757_35210#
name2 = POWER_RAIL_COR_0/POWER_RAIL_COR_0_0/POWER_RAIL_COR_1_0/a_13097_44708#
(both of these are VSS; the bottom one is the "other" side of a split tile)
(??) not clear these are even in a ground domain?
name1 = GF_NI_COR_BASE_0/power_via_cor_5_0/m1_14757_49610#
name2 = POWER_RAIL_COR_0/POWER_RAIL_COR_0_0/POWER_RAIL_COR_1_0/a_13097_44708#
(both of these are VSS; the bottom one is the "other" side of a split tile)
That was it, though. . .
I thought this would be hard, but it's still harder than I thought.
Time for a brute-force approach.
Good. Listing all of the VSS entries above and checking against all of them
produces only a handful of places where there were two entries and only one of
them was in the list.
1st: GF_NI_COR_BASE
name2 = comp018green_esd_clamp_v5p0_1_0/top_route_0/m1_6892_106#
Check, but looks okay. (checked.)
2nd: POWER_RAIL_COR_0
name2 = POWER_RAIL_COR_1_0/VSS, missing from list.
3rd: POWER_RAIL_COR:
name2 = POWER_RAIL_COR_0_0/VSS, missing from list.
4th: gf180mcu_ocd_io__cor:
name1 = GF_NI_COR_BASE_0/power_via_cor_3_0/m1_14757_35210#
name2 = POWER_RAIL_COR_0/POWER_RAIL_COR_0_0/POWER_RAIL_COR_1_0/a_13097_44708#
(to be checked)
5th: gf180mcu_ocd_io__cor:
name1 = GF_NI_COR_BASE_0/power_via_cor_3_0/m2_12842_49632#
name2 = POWER_RAIL_COR_0/POWER_RAIL_COR_0_0/VSS
(to be checked, but looks okay)
6th: gf180mcu_ocd_io__cor:
name1 = GF_NI_COR_BASE_0/power_via_cor_3_0/m2_8733_41714#
name2 = POWER_RAIL_COR_0/POWER_RAIL_COR_0_0/VSS
(to be checked, but looks okay)
7th: gf180mcu_ocd_io__cor:
name1 = GF_NI_COR_BASE_0/power_via_cor_3_0/m2_7640_52771#
name2 = POWER_RAIL_COR_0/POWER_RAIL_COR_0_0/VSS
(to be checked, but looks okay)
MORE brute force. . .
Okay, found something: This is in the 2nd location where the second name is
not explicitly defined.
1st: name "comp018green_esd_clamp_v5p0_1_0/top_route_0/m1_6892_106#", looks okay.
(also, not in the top level)
2nd: name1 "GF_NI_COR_BASE_0/dw_13436_13361x#" vs.
name2 "POWER_RAIL_COR_0/POWER_RAIL_COR_0_0/POWER_RAIL_COR_1_0/a_13097_44708#"
(check this)
3rd: node1 length 41, node2 length 6. node1 detected as dvss, node2 as vss.
node2 components:
POWER_RAIL_COR_0/POWER_RAIL_COR_0_0/VSS
VSS
GF_NI_COR_BASE_0/power_via_cor_3_0/m2_12842_35238#
GF_NI_COR_BASE_0/power_via_cor_3_0/m2_8741_35238#
GF_NI_COR_BASE_0/comp018green_esd_clamp_v5p0_1_0/comp018green_esd_rc_v5p0_1_0/VMINUS
GF_NI_COR_BASE_0/power_via_cor_3_0/m2_6358_35238#
node1 components:
GF_NI_COR_BASE_0/moscap_corner_3/VMINUS
GF_NI_COR_BASE_0/power_via_cor_3_0/m1_14757_35210#
node1 was already compromised. power_via_cor_3 should not have ended up in the
DVSS list. Check specifically for this.
Spot 2, iteration 622, node1 (length 1) =
GF_NI_COR_BASE_0/power_via_cor_3_0/m1_14757_35210#
node2 (length 40) = GF_NI_COR_BASE_0/moscap_corner_3/VMINUS
Check other node2 names:
GF_NI_COR_BASE_0/moscap_routing_0/m1_n33412_n19921# (and similar)
GF_NI_COR_BASE_0/moscap_routing_0/a_n47022_n23957# (and similar)
POWER_RAIL_COR_0/POWER_RAIL_COR_0_0/POWER_RAIL_COR_1_0/a_13097_44708#
GF_NI_COR_BASE_0/dw_13436_13361#
GF_NI_COR_BASE_0/dw_13436_13361x# <-- smoking gun? Cannot be BOTH sides.
"w_13448_13361# <-- is not pointing to the opposite side. . .
After a diversion to correct the "goto" command for split tiles. . .
node1 (length 1) = w_13448_13361#
node2 (length 1) = GF_NI_COR_BASE_0/dw_13436_13361x#
There lies the smoking gun.
At line 690 (3rd spot)
node1 corresponds to cum = pwell on right side. It should have an "x" in
the name. Tile at 43803, 14403.
. . . which makes it no longer a smoking gun (maybe?), although now I need
to find out why the node name doesn't have an "x".
How about
node1 = GF_NI_COR_BASE_0/dw_13436_13361# (VSS)
node2 = GF_NI_COR_BASE_0/moscap_corner_3_0/VMINUS (DVSS) ?
Except dw and dwx are now already both on the same node.
Still not getting it.
Again?
Okay, problem is that the incorrect merge wasn't checked for
specifically, but can do that now. Looks like:
POWER_RAIL_COR_0/POWER_RAIL_COR_0_0/POWER_RAIL_COR_1_0/a_13097_44708# (VSS)
and GF_NI_COR_BASE_0/dw_13436_13361x# (DVSS)
Now:
node1 = GF_NI_COR_BASE_0/dw_13436_13361x# and
"w_13448_13361#
node2 = POWER_RAIL_COR_0/POWER_RAIL_COR_0_0/POWER_RAIL_COR_1_0/a_13097_44708#
cum = split tile, dir = 1, isosub on right side, position 43803, 14403
(43803, 14403) to (43898, 14498).
clearly correct for DVSS.
ha->hierOneTile = split tile, dir = 1, psd on left side, pos. 43718, 14336.
(43718, 14336) to (43880 14498).
These appear to be overlapping. What's up?
*** Okay, this is definitely the smoking gun. The two triangular regions do
not overlap but the rectangles do.
Who is looking at what side?
dinfo, associated with cum, has TT_SIDE set, so looking at isosub, therefore
DVSS.
ha->hierOneTile does *not* have TT_SIDE set, so looking at psd on left side.
Okay, the error is: ExtHier.c checks if the tiles touch, but does not
check if two *split* tiles touch or not.
First try at the disjoint triangle routine failed. Gotta do the math.
Ahhh. . . Not 100% sure the code is right but I finally got a netlist that
is correct. And the corner cell now passes LVS.
-------------------End of digression
Back to sky130 gpiov2 I/O cell.
Still have to deal with the fact that the top_gpiov2 cell no longer passes LVS
when it used to pass LVS, and the device count mismatches by three with metal1
resistors.
At top_gpiov2 top level, check the VSSD net:
In particular, most connections are the same except one nfet device, and
(easier to find) sky130_fd_io__com_cclat/PU_DIS_H on the layout side at
one 3.3V pFET drain/source on the layout side; the latter seems suspicious
because the schematic netlist does not show any pFETs tied to ground.
The issue with the gpiov2 cell looks like it might actually be relevant to
the issue just fixed (or just attempted), because the PU_DIS_H line is close
to ground along a diagonal, with diagonal lines from different cells overlapping.
The directions of overlap are different from the example just fixed, so
algorithmic errors are possible. . .
Cell sky130_fd_io__com_opath_datoev2.ext merges sky130_fd_io__com_cclat_0/PU_DIS_H
with VGND.
NOTE: Selecting VGND in top_gpiov2 and doing "getnode" resulted in an immediate
crash. Fix this first.
Uh. . . Also: Selecting the VGND corner there *also* selects the PU_DIS_H wire
in the same box area, which is wrong and didn't happen before. This with just
a "select chunk".
But the crash first. . .
ExtBasic.c:960 ll is invalid.
"node" is wrong. lreg->next is CLIENTDEFAULT.
Came from "SimGetNodeName" so SimExtract.c probably has code that needs updating.
Okay, found one. . . (fixed)
Another NOTE: Haven't been able to get "getnode" to work on a large layout and
this needs significant work. Maybe revisit whether code in sim/ is really
necessary for that. Getting a node name should be very fast. Why isn't it?
First, avoid unnecessary overhead by seeing if the same extract error happens
from the .mag version. Yes, it does. And indeed, ExtHier.c:153 is reached
on sky130_fd_io__com_opath_datoev2.
cum = metal1 on right side of split tile at (6412, 1058) to (6461, 1107).
ha->hierOneTile = metal1 on left side of split tile at (6392, 845) to (6633, 1086).
Because I have clearly made bad assumptions in my routine to check if tiles
overlap, I have turned to ChatGPT to tell me how to write a routine checking
the overlap of two split tiles.
Reworked a bunch of code around, this, and consolidated the non-Manhattan
interaction test between the database code for DBSrPaintNMArea() and the
extraction.
Oh, dear, things seem to have been made worse. PU_DIS_H in cclat is still
being connected to VSSD, but now a number of other signals are also being
connected to VSSD.
Debugging: extHierConnectFunc2():
Break on dbEvalCorner().
cum = metal1 on right side of split tile at (6412, 1058) to (6461, 1107).
ha->hierOneTile = metal1 on left side of split tile at (6392, 845) to (6633, 1086).
At least it has determined that these two tiles are facing opposite directions
and need the corner evaluation.
1st call: p = (6412, 1058)
r1 = (6412, 1058) to (6461, 1107)
di1 = split | direction | side.
r2 = (6392, 845) to (6633, 1086)
di2 = split | direction
in DBTestNMInteract, r (the area of overlap) is (6412, 1058) to (6461, 1086) (okay)
1st call: p = (6412, 1058) v = -473 (set vmin to this)
2nd call: p = (6461, 1086) v = -15257 (set vmin to this)
3rd call: p = (6412, 1086) v = -5849 (no action)
4th call: p = (6461, 1058) v = -9881 (no action)
Okay, fixed the problem with v needing to be initialized by the first corner. . .
At least that's what ChatGPT says. But it's still failing.
1st call: p = (6412, 1058) v = -473 (set vmin and vmax to this)
2nd call: p = (6461, 1086) v = -15257 (set vmin to this)
3rd call: p = (6412, 1086) v = -5849 (no action)
4th call: p = (6461, 1058) v = -9881 (no action)
That worked, but. . . PU_DIS_H is still shorted to VGND in the .ext file. . .
When does DBTestNMInteract() return TRUE for the hard case?
Here we have area (7019, 1033) to (7044, 1058). dir = 1, side = 1.
Tile t2 is at (7019, 1040) and is type metal1 on the right side, dir = 1.
This routine is doing a search for "dbcUnconnectFunc()" and so is searching
for non-connecting types (including TT_SPACE) overlapping the area.
Tile t2 is (7019, 1040) to (7037, 1058).
Now I recognize a serious problem, which is that the extract routine is
looking for "interacting" shapes whereas DBSrPaintNMArea should be looking
for "overlapping" shapes, and these two cases must be clearly disambiguated.
(fixed)
But still fails.
Gave up on what ChatGPT produced and did something similar but different.
Cases are still failing and connectivity always goes into an infinite loop
but at least I understand the algorithm and equations.
Now: Again, rect1 is (6412, 1058) to (6461, 1107). tt1 has DIR and SIDE set.
t2 is at (6392, 845), DIR only.
Corner evaluation:
lower left = -1
upper left = -1
lower right = -1
Upper right corner is skipped.
SIDE and DIR are set, so neg = 3 becomes pos = 3.
Evaluates to "fully disjoint", which is correct.
That was the only time this was called. . .
Then maybe better to figure out the problem with net selection?
Loaded sky130_fd_io__gpio_dat_ls_1v2 and selected VGND close to the bottom, m1.
Got a break on dbEvalCorner.
DBTestNMInteract() called with rect1 = (705, 1455) to (749, 1499), tt1 = DIR only.
t2 at 705, 1455 is split m1 tile, m1 on left side, DIR=1.
Got value -3, indicates fully enclosed. Is it?
Yes, but the sides are the same, so why is it in dbEvalCorner?
tt2 *does* have SIDE set. In which case they should be touching/nonoverlapping.
Why is it even looking on that side? Yes, this is dbcUnconnectFunc.
So this case fails. Easy to check. Works in the python code. What's different?
Upper right check, . . . Oh. "r" still used but never defined.
Selection now works, but it is now showing PU_DIS_H shorted to VSSD (when PU_DIS_H
is selected, but not when VSSD is selected).
If PU_DIS_H is selected on the straight wire to the right of the angled area,
DBTestNMInteract() is called with rect1 = (7019, 1033) to (7044, 1058).
tt1 has SIDE=1, DIR=1. t2 at (7019, 1040) has metal1 on right side, DIR=1, SIDE=0.
1st call is -1, 2nd is 0, 3rd is 0. SIDE=DIR in area, so result becomes pos=1,
touch=2. pos+touch=3 so returns FALSE (unenclosed but touching). Is that right?
Yes, the left side of the tile is space and the areas don't interact.
Note there is also a weird case below the area where the selection. . . okay,
that thing is actually real.
Try again selecting the shape to the left of the area of concern.
rect1 = (6378, 1161) to (6424, 1207), tt1 = DIR=1, SIDE=1
tp2 @ (6378, 1161), metal1 on left, DIR=1, SIDE=0. That's not the problem
area, either.
Try again with the extraction. Need to catch the nodes getting merged.
That wasn't very productive. Probably better to go back to selecting
PU_DIS_H and cycle through until the jump to VSSD occurs.
Note: The node name of PU_DIS_H at the top level in the .mag file (because
the label isn't properly connected) is "li_5797_1167#". It did show up in
the extraction, being connected to ?/OUT_H_N, which layer is connected
to ?cclat_0/VGND.
Back to selection. When selecting the shape to the left of the area of
concern, as mentioned above, here is the sequence of areas passed to
DBTestNMInteract() when breaking at line 201 at the start of the "hard case":
{p_x = 6378, p_y = 1161}, r_ur = {p_x = 6424, p_y = 1207}
{p_x = 6377, p_y = 1160}, r_ur = {p_x = 6424, p_y = 1207}
{p_x = 6378, p_y = 1161}, r_ur = {p_x = 6424, p_y = 1207}
{p_x = 6358, p_y = 1107}, r_ur = {p_x = 6412, p_y = 1161} * not overlapping
{p_x = 6412, p_y = 1058}, r_ur = {p_x = 6462, p_y = 1108} * overlapping
{p_x = 6424, p_y = 1107}, r_ur = {p_x = 6478, p_y = 1161}
{p_x = 6412, p_y = 1058}, r_ur = {p_x = 6461, p_y = 1107} * overlapping
{p_x = 82, p_y = 1058}, r_ur = {p_x = 132, p_y = 1108} (?)
...
Take the starred entries in turn:
Area 6358 1107 6412 1161 DIR=1 SIDE=1. t2@(6358, 1107) DIR=1 SIDE=0 metal1 on right
check is on space side of tile, so result should be disjoint (false)
pos = 1, touch = 2, returns false (correct)
Area 6412 1058 6462 1108 DIR=1 SIDE=1. t2@(6424, 1107) DIR=1 SIDE=0 metal1 on left
check is on metal side of tile, tile is in the same net, should connect (true)
neg = 3, returns true (correct, I think)
Area 6412 1058 6461 1107 DIR=1 SIDE=1. t2@(6412, 1058) DIR=1 SIDE=0 metal1 on right
check is on space side of tile.
pos = 1, touch = 2 returns false.
Seems like it is checking the wrong thing, like t2.
Actually the next entry is the interesting one. The position (82, 1058) is
the location in subcell sky130_fd_io__com_cclat of the overlapping tile from
the parent cell. This is probably what needs inspecting.
Area 82 1058 132 1108 DIR=1 SIDE=1. t2@(62, 845) DIR=1 SIDE=0 metal1 on left side.
This is clearly checking the wrong side; maybe tt1 is not being adjusted for the
child use transform? Or is it suspicious that DIR and SIDE are always 1?
Going up the call stack, the tile is indeed in sky130_fd_io__com_cclat.
dinfo *has* been transformed to scx->trans. dinfo = DIR=1, SIDE=1.
new dinfo = DIR=1, SIDE=1. Trans = [1 0 6330 0 1 0] which is just a translation
(correct).
Going up further in the stack:
DBTreeCopyConnect() calls DBTreeSrNMTiles with
scx->scx_area == (6412, 1058) to (6462, 1108), dinfo = DIR=1, SIDE=1 (confirmed)
In the child cell, this search becomes area (82, 1058) to (132, 1108) (confirmed)
with the same split information (DIR=1, SIDE=1). "mask" contains only metal1.
Calls DBTestNMInteract to check this area againsst the tila at (62, 845)
which is a split tile with metal on the left side. This check should go to the
hard case (correct) but should return a result of "disjoint".
rect2 = (62, 845) to (303, 1086).
Should evaluate lower left, upper left, and lower right.
lower left: result -1
upper right is skipped (correct)
upper left: result -1
lower right: result -1
returns FALSE (fully disjoint) (correct).
Okay, so that wasn't a smoking gun.
Keep looking.
When does it jump to the VSSD region?
(locations after area 82 1058 132 1108 above)
6412 1058 6461 1107: Overlap region again
7019 1033 7044 1058: Right side of PU_DIS_H (corner fillet)
7019 1033 7044 1058: again
7019 1033 7044 1058: and again
6412 1058 6461 1107: Back to the region of interest overlap
6478 1086 6499 1107: Position facing inward
6391 844 6633 1086: This is in VSSD. What is it doing here?
Something happened in the previous three checks? They didn't look
interesting. . . Check where the t2 tile is in each case.
Uhh. . .
Back to Area 82 1058 132 1108, tile is @(62, 845) confirmed above that result
is disjoint.
I'm thinking that something is logically incorrect before it gets to line 201?
Start looking at *all* calls to DBTestNMInteract(), find a t2 that belongs
to VSSD, and then find when DBTestNMInteract returns TRUE.
Here's a new one:
area 147 1085 169 1107
checks against tile (62 845) in cclat
returned true (but should not have).
Oof---at line 190, returned "true"
Tiles have the same TT_SIDE but not interact.
In this case, no part of the *rectangle* of t2 is in the area of rect1. So
it should have returned FALSE from the code above, but didn't.
No, that's not right. Here, t2 is the larger rectangle, so t2 definitely
overlaps rect1.
Maybe it's sufficient to just remove that line? Won't the rest of the code
determine the interaction correctly, regardless of how TT_SIDE is set?
Let's try it!
Didn't work. . . maybe the pos/neg swap is wrong in this case?
(Note: Found this by breaking on DBTestNMInteract when
t2->ti_ll.p_x == 62 && t2->ti_ll.p_y == 845
2nd time was the one that failed.
Keep forgetting that t2 is the larger rectangle.
Implemented something but assumptions still seem to be wrong.
Actually, just missing parentheses.
Finally, it's working!!!
Still errors on top_gpiov2 but VSSD now matches, so that part of the
extraction was correct.
Investigating the remaining top_gpiov2 errors:
Mismatch of three rm1 resistors may be coming from sky130_fd_io__gpiov2_octl_dat.
Can try a "noflatten" on that cell and see.
My have another digression because netgen crashed. (Fixed, needs attention later)
Worse, the GDS-derived netlist and the .mag-derived netlist differ, with netgen
reporting not only the three metal 1 resistors, but now also a metal 3 resistor.
Check sky130_fd_io__sio_signal_5_sym_hv_local_5term?
I think there may be a discrepency between the use of this in the ovtv2 pad
and the gpiov2 pad. The netlist "incorrectly" uses the ovtv2 version of
buf_localesd in the gpiov2 pad.
sky130_fd_io__gpiov2_octl_dat layout has a split DM_H[1] pin (confirm?).
This prevents correct LVS, but if it is flattened, then additional rm1
devices appear.
Need unrelated work: "ad" and "pd" values (usually) match relative to what
magic used to produce, but "as" and "ps" are way off. Something's up with that.
Just noticed that res_generic_m1 devices are being removed, counting as
"zero valued" resistors. But they aren't zero-valued; they're semiconductor
resistors, and that should never happen and is netgen's fault. And I need
regression tests. . .
According to netgen code, that should not have happened. Indeed, error got
introduced accidentally into netgen last month. Fixed.
That seems to have gotten the top_gpiov2 cell back into striking range of
LVS clean. The most obvious issue left is that ENABLE_H is connected to
1 each 3.3V nFET and pFET devices in the layout but 3 each in the netlist.
Layout shows definitely connected to 6 devices. Extraction error?
Layout also shows that sky130_fd_io__gpiov2_ctl has all of the transistors
but they're broken into two unconnected groups. The labeled group of four
is getting disconnected, and this is almost certainly an introduced
extraction error (dang.).
Name of disconnected part of the net is a_11799_3638# in sky130_fd_io__gpiov2_ctl.
This is correctly listed as a port of gpiov2_ctl after DM[1], the 19th port.
However, that's the part that is found. The part of the net labeled ENABLE_H
is the 6th port.
In sky130_fd_io__top_gpiov2, the call to sky130_fd_io__gpiov2_ctl has
as the 6th port "sky130_fd_io__gpiov2_ctl_0/ENABLE_H" and as 19th port
ENABLE_H, so this is unfortunately a merge that failed to happen.
Re-extract and inspect the .ext files. (Although technically, need to follow
the GDS import from the script to make a 1:1 comparison.) (Both files are the
same, so it's okay to use the .mag for extraction testing.).
ctl_0/ENABLE_H does not even appear in the .ext file.
Will have to track down how the net connectivity of ENABLE_H is traced in
the extraction. How could it miss just one connection of one net?
If I punt on this one by correcting it manually in the netlist, then there
is still a failure in which "sky130_fd_io__top_gpiov2_0/\
sky130_fd_io__gpio_opathv2_0/sky130_fd_io__gpio_odrvrv2_0/PU_H_N[0]" has
also been disconnected. But this follows a ridiculously long and winding
path, and looks like it has a good chance of being produced by the same
bug, and I'd rather debug from the ENABLE_H signal. Also it's harder to
figure out what to change in the netlist to correct it manually.
Most likely involves a plane-to-plane connection through a via

View File

@ -817,7 +817,7 @@ CIFTechLine(
else
{
l = strlen(CIFCurStyle->cs_name) - strlen(tptr);
if (!strcmp(tptr, CIFCurStyle->cs_name + l))
if ((l > 0) && !strcmp(tptr, CIFCurStyle->cs_name + l))
{
CIFCurStyle->cs_status = TECH_PENDING;
return TRUE;

View File

@ -1613,7 +1613,7 @@ CmdFindNetProc(
int pnum, xpos, ypos;
char *xstr, *ystr;
bool locvalid = FALSE, usefound = TRUE;
TileType ttype;
TileType ttype, dinfo = (TileType)0;
scx.scx_use = use;
scx.scx_trans = GeoIdentityTransform;
@ -1651,6 +1651,7 @@ CmdFindNetProc(
if ((xstr = strchr(s, '_')) != NULL)
{
char *hashpos;
bool isNeg = FALSE;
/* The characters up to the leading '_' should match one of the */
@ -1694,6 +1695,17 @@ CmdFindNetProc(
}
}
}
/* Format variant used for node regions where a split tile
* occupies the root position of the node but the tile type
* belonging to the node is on the right side of the tile,
* not at the location encoded into the name. An 'x' is
* added before the final hash sign.
*/
hashpos = strrchr(s, '#');
if (hashpos != NULL)
if (*(hashpos - 1) == 'x')
dinfo = TT_DIAGONAL | TT_SIDE;
}
}
@ -1716,17 +1728,23 @@ checklocal:
if (locvalid == TRUE)
{
int findTile(Tile *tile, TileType dinfo, TileType *rtype);
int findTile(Tile *tile, TileType dinfo, TileAndDinfo *tad);
CellDef *targetdef = use->cu_def;
Plane *plane = targetdef->cd_planes[pnum];
ttype = TT_SPACE; /* revert to space in case of failure */
TileAndDinfo tad;
/* Find the tile type of the tile at the specified point which */
/* exists on the plane pnum. */
/* exists on the plane pnum. Note that in the case of a split */
/* tile region marked with "x" in the name, it does not work to */
/* call DBSrPainNMArea() because the diagonal position is not */
/* known. findTile() determines the proper type and leaves it */
/* in the tad.tad_dinfo record. */
tad.tad_tile = (Tile *)NULL;
tad.tad_dinfo = dinfo;
DBSrPaintArea(NULL, plane, &localrect, &DBAllTypeBits, findTile,
(ClientData) &ttype);
(ClientData) &tad);
ttype = tad.tad_dinfo & TT_LEFTMASK;
}
else
{
@ -1850,21 +1868,31 @@ CmdGoto(
int
findTile(
Tile *tile,
TileType dinfo,
TileType *rtype)
TileType dinfo, /* (unused) */
TileAndDinfo *tad)
{
TileType ttype;
/* Note that since all types are being searched, a split
* tile would cause the callback to be called twice. But
* this routine will pick the indicated side from the
* "tad" structure and return 1 so it does not get called
* a second time. The "dinfo" value passed is irrelevant.
*/
if (IsSplit(tile))
{
if (dinfo & TT_SIDE)
if (tad->tad_dinfo & TT_SIDE)
ttype = SplitRightType(tile);
else
ttype = SplitLeftType(tile);
}
else
ttype = TiGetTypeExact(tile);
*rtype = ttype;
/* Leave the tile type in tad_dinfo before returning */
tad->tad_dinfo = ttype;
return 1; /* stop search */
}

View File

@ -128,87 +128,6 @@ DBInvTransformDiagonal(oldtype, trans)
return dinfo;
}
/*
* ----------------------------------------------------------------------------
*
* DBSrConnectOnePlane --
*
* Search from a starting tile to find all paint that is electrically
* connected to that tile in the same plane.
*
* Results:
* 0 is returned if the search finished normally. 1 is returned
* if the search was aborted.
*
* Side effects:
* For every paint tile that is electrically connected to the initial
* tile, func is called. Func should have the following form:
*
* int
* func(tile, clientData)
* Tile *tile;
* TileType dinfo;
* ClientData clientData;
* {
* }
*
* The clientData passed to func is the same one that was passed
* to us. Func returns 0 under normal conditions; if it returns
* 1 then the search is aborted.
*
* *** WARNING ***
*
* Func should not modify any paint during the search, since this
* will mess up pointers kept by these procedures and likely cause
* a core-dump.
*
* ----------------------------------------------------------------------------
*/
int
DBSrConnectOnePlane(startTile, dinfo, connect, func, clientData)
Tile *startTile; /* Starting tile for search */
TileType dinfo; /* Split tile information */
TileTypeBitMask *connect; /* Pointer to a table indicating what tile
* types connect to what other tile types.
* Each entry gives a mask of types that
* connect to tiles of a given type.
*/
int (*func)(); /* Function to apply at each connected tile. */
ClientData clientData; /* Client data for above function. */
{
struct conSrArg csa;
int result;
result = 0;
csa.csa_def = (CellDef *)NULL;
csa.csa_bounds = TiPlaneRect;
/* Pass 1. During this pass the client function gets called. */
csa.csa_clientFunc = func;
csa.csa_clientData = clientData;
csa.csa_clientDefault = startTile->ti_client;
csa.csa_clear = FALSE;
csa.csa_connect = connect;
csa.csa_pNum = -1;
if (dbSrConnectFunc(startTile, dinfo, PTR2CD(&csa)) != 0) result = 1;
/* Pass 2. Don't call any client function, just clear the marks.
* Don't allow any interruptions.
*/
SigDisableInterrupts();
csa.csa_clientFunc = NULL;
csa.csa_clear = TRUE;
(void) dbSrConnectFunc(startTile, dinfo, PTR2CD(&csa));
SigEnableInterrupts();
return result;
}
/*
* ----------------------------------------------------------------------------
*
@ -290,6 +209,7 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData)
*/
start_tad.tad_tile = NULL;
start_tad.tad_next = NULL; /* unused */
for (startPlane = PL_TECHDEPBASE; startPlane < DBNumPlanes; startPlane++)
{
csa.csa_pNum = startPlane;
@ -383,6 +303,7 @@ DBSrConnectOnePass(def, startArea, mask, connect, bounds, func, clientData)
*/
tad.tad_tile = NULL;
tad.tad_next = NULL; /* unused */
for (startPlane = PL_TECHDEPBASE; startPlane < DBNumPlanes; startPlane++)
{
csa.csa_pNum = startPlane;

View File

@ -44,6 +44,296 @@ struct dbCheck
int dbCheckMaxHFunc(), dbCheckMaxVFunc();
/*
* --------------------------------------------------------------------
*
* dbEvalCorner --
*
* Used by DBTestNMInteract() to determine whether two non-
* Manhattan areas have crossing diagonals by evaluating the
* corner points of the area of intersection between the two
* tiles. This routine finds the distance from a point in
* the second triangle to the diagonal of the first, in both
* x and y. If the point is below or to the left, the
* distance is negative; otherwise the distance is positive.
*
* Results:
* 1 for a positive result, -1 for a negative result, and 0
* for the same result (point touches the diagonal).
*
* Side effects:
* None.
*
* --------------------------------------------------------------------
*/
int
dbEvalCorner(Point *p, // Point to evaluate
Rect *rect, // Triangular area bounding rectangle
TileType di) // Diagonal information for split rect
{
dlong D;
/* D is the distance from a point to the diagonal of the rectangle.
* The magnitude is not important. It only matters what the sign
* is, so return 1 for positive, -1 for negative, or 0.
*/
if (di & TT_DIRECTION)
D = (p->p_y - rect->r_ybot) * (rect->r_xtop - rect->r_xbot) -
(rect->r_xtop - p->p_x) * (rect->r_ytop - rect->r_ybot);
else
D = (p->p_y - rect->r_ybot) * (rect->r_xtop - rect->r_xbot) -
(p->p_x - rect->r_xbot) * (rect->r_ytop - rect->r_ybot);
if (D > 0) return 1;
if (D < 0) return -1;
return 0;
}
/*
* --------------------------------------------------------------------
*
* DBTestNMInteract --
*
* Determine if a tile (t2) interacts with (touches or overlaps)
* a triangular area (rect1, with diagonal split information in
* di1). Tile t2 may or may not be a split tile. If t2 is
* split, then diagonal split information is in di2.
*
* There are two distinct cases: DBSrPaintNMArea() looks for
* tiles that overlap the area of rect1, but extTestNMInteract()
* looks for tiles that both overlap or touch (indicating
* electrical connectivity between the two). "overlap_only"
* distinguishes between the two use cases. Set "overlap_only"
* to TRUE for overlap searches, and FALSE for interaction
* searches.
*
* Results:
*
* If overlap_only is TRUE:
* Return TRUE if the indicated areas overlap, FALSE if not.
* If overlap_only is FALSE:
* Return TRUE if the indicated areas touch or overlap, FALSE if not.
*
* Side effects:
* None.
*
* --------------------------------------------------------------------
*/
bool
DBTestNMInteract(Rect *rect1,
TileType tt1,
Tile *t2,
TileType di2,
bool overlap_only)
{
Rect rect2, r;
Point p;
int rheight, rwidth, rmax;
dlong f1, f2, f3, f4;
TileType tt2;
int pos, neg, touch, sign;
TiToRect(t2, &rect2);
/* Assuming that rect1 is a split area, then check if any part of t2
* overlaps the split side of interest in rect1, regardless of whether
* t2 is split or not. If there is no overlap, then return FALSE.
*/
rheight = rect1->r_ytop - rect1->r_ybot;
rwidth = rect1->r_xtop - rect1->r_xbot;
rmax = MAX(rheight, rwidth);
f1 = (rect2.r_ybot > MINFINITY + 2) ?
((dlong)(rect1->r_ytop - rect2.r_ybot) * rwidth) : DLONG_MAX;
f2 = (rect2.r_ytop < INFINITY - 2) ?
((dlong)(rect2.r_ytop - rect1->r_ybot) * rwidth) : DLONG_MAX;
if (tt1 & TT_SIDE)
{
/* Outside-of-triangle check---ignore sub-integer slivers */
if (rect2.r_xtop < INFINITY - 2)
{
f3 = (dlong)(rect1->r_xtop - rect2.r_xtop) * rheight;
f3 += rmax;
}
else
f3 = DLONG_MIN;
if ((tt1 & TT_DIRECTION) ? (f2 < f3) : (f1 < f3))
return FALSE;
}
else
{
/* Outside-of-triangle check---ignore sub-integer slivers */
if (rect2.r_xbot > MINFINITY + 2)
{
f4 = (dlong)(rect2.r_xbot - rect1->r_xbot) * rheight;
f4 += rmax;
}
else
f4 = DLONG_MIN;
if ((tt1 & TT_DIRECTION) ? (f1 < f4) : (f2 < f4))
return FALSE;
}
/* If t2 is not split, or its diagonal is the opposite of t1,
* or its side is the same as that of t1, then they overlap.
*/
if (!IsSplit(t2)) return TRUE;
tt2 = TiGetTypeExact(t2) | di2;
if ((tt1 & TT_DIRECTION) != (tt2 & TT_DIRECTION)) return TRUE;
// if ((tt1 & TT_SIDE) == (tt2 & TT_SIDE)) return TRUE;
/* Hard case: Same diagonal direction, opposite sides. To determine
* overlap, count which of the three points of triangle t2 land on
* one side or the other of the rect1 split diagonal. From those
* counts, determine if the triangles are overlapping, touching,
* or disjoint.
*/
/* Evaluate the three corners of the rect2 triangle */
pos = neg = touch = 0;
if (!(tt2 & TT_DIRECTION) || !(tt2 & TT_SIDE))
{
/* Evaluate the lower left corner */
sign = dbEvalCorner(&rect2.r_ll, rect1, tt1);
if (sign == 1)
pos++;
else if (sign == -1)
neg++;
else
touch++;
}
if (!(tt2 & TT_DIRECTION) || (tt2 & TT_SIDE))
{
/* Evaluate the upper right corner */
sign = dbEvalCorner(&rect2.r_ur, rect1, tt1);
if (sign == 1)
pos++;
else if (sign == -1)
neg++;
else
touch++;
}
if ((tt2 & TT_DIRECTION) || !(tt2 & TT_SIDE))
{
/* Evaluate the upper left corner */
p.p_x = rect2.r_xbot;
p.p_y = rect2.r_ytop;
sign = dbEvalCorner(&p, rect1, tt1);
if (sign == 1)
pos++;
else if (sign == -1)
neg++;
else
touch++;
}
if ((tt2 & TT_DIRECTION) || (tt2 & TT_SIDE))
{
/* Evaluate the lower right corner */
p.p_x = rect2.r_xtop;
p.p_y = rect2.r_ybot;
sign = dbEvalCorner(&p, rect1, tt1);
if (sign == 1)
pos++;
else if (sign == -1)
neg++;
else
touch++;
}
/* If side and direction match, then pos and neg need to be swapped */
if (((tt1 & TT_SIDE) && (tt1 & TT_DIRECTION)) ||
(!(tt1 & TT_SIDE) && !(tt1 & TT_DIRECTION)))
{
int temp = neg;
neg = pos;
pos = temp;
}
/* Return TRUE or FALSE depending on the values of pos, neg, and
* touch, and depending on whether overlap_only is set or not.
*/
if (pos == 3)
return FALSE; /* Fully disjoint */
else if (neg == 3)
{
if ((tt1 & TT_SIDE) != (tt2 & TT_SIDE))
return TRUE; /* Fully enclosed */
else
{
/* This is a trickier situation. Both triangles have
* the same TT_SIDE bit, but the triangular area of t2
* could still be outside of rect1. Need to check where
* the inside corner of rect1 lands with respect to the
* t2 diagonal.
*/
if (((tt1 & TT_SIDE) == 0) && ((tt1 & TT_DIRECTION) != 0))
{
sign = dbEvalCorner(&rect1->r_ll, &rect2, tt2);
}
else if (((tt1 & TT_SIDE) == 0) && ((tt1 & TT_DIRECTION) == 0))
{
p.p_x = rect1->r_ll.p_x;
p.p_y = rect1->r_ur.p_y;
sign = dbEvalCorner(&p, &rect2, tt2);
}
else if (((tt1 & TT_SIDE) != 0) && ((tt1 & TT_DIRECTION) == 0))
{
p.p_x = rect1->r_ur.p_x;
p.p_y = rect1->r_ll.p_y;
sign = dbEvalCorner(&p, &rect2, tt2);
}
else /* if (((tt1 & TT_SIDE) != 0) && ((tt1 & TT_DIRECTION) != 0)) */
{
sign = dbEvalCorner(&rect1->r_ur, &rect2, tt2);
}
/* Again, if side and direction match, then sign is backwards
*/
if (((tt2 & TT_SIDE) && (tt2 & TT_DIRECTION)) ||
(!(tt2 & TT_SIDE) && !(tt2 & TT_DIRECTION)))
sign = -sign;
if (sign == 1)
return FALSE; /* Fully disjoint */
else if (sign == -1)
return TRUE; /* Fully overlapping */
else if (overlap_only)
return FALSE; /* Touching but not overlapping */
else
return TRUE; /* Touching but not overlapping */
}
}
else if (overlap_only)
{
if ((touch > 0) && (neg + touch == 3))
return TRUE; /* Enclosed and touching */
else if ((touch > 0) && (pos + touch == 3))
return FALSE; /* Unenclosed but touching */
else
return TRUE; /* Partially overlapping */
}
else /* overlap_only == FALSE */
{
if ((touch > 0) && (neg + touch == 3))
return TRUE; /* Enclosed and touching */
else if ((touch > 0) && (pos + touch == 3))
return TRUE; /* Unenclosed but touching */
else
return TRUE; /* Partially overlapping */
}
}
/*
* --------------------------------------------------------------------
*
@ -138,6 +428,28 @@ nm_enum:
/* the tile enumeration if it is not. */
/* Watch for calculations involving (M)INFINITY in tile (tp)! */
if (IsSplit(tp))
{
TileType tpdi = TiGetTypeExact(tp);
if (TTMaskHasType(mask, SplitLeftType(tp)))
if (DBTestNMInteract(rect, ttype, tp, tpdi, TRUE))
if ((*func)(tp, (TileType)TT_DIAGONAL, arg))
return 1;
if (TTMaskHasType(mask, SplitRightType(tp)))
if (DBTestNMInteract(rect, ttype, tp, tpdi | TT_SIDE, TRUE))
if ((*func)(tp, (TileType)TT_DIAGONAL | TT_SIDE, arg))
return 1;
}
else
{
if (TTMaskHasType(mask, TiGetType(tp)))
if (DBTestNMInteract(rect, ttype, tp, (TileType)0, TRUE))
if ((*func)(tp, (TileType)0, arg))
return 1;
}
#if 0
rheight = rect->r_ytop - rect->r_ybot;
rwidth = rect->r_xtop - rect->r_xbot;
rmax = MAX(rheight, rwidth);
@ -277,6 +589,7 @@ nm_enum:
else
if (TTMaskHasType(mask, TiGetType(tp)) && (*func)(tp, (TileType)0, arg))
return (1);
#endif
enum_next:
tpnew = TR(tp);
@ -736,7 +1049,12 @@ DBResetTilePlaneSpecial(plane, cdata)
enumerate:
if (IsSplit(tp))
if ((TiGetLeftType(tp) != TT_SPACE) && (TiGetRightType(tp) != TT_SPACE))
freeMagic(tp->ti_client);
if (tp->ti_client != cdata)
{
ASSERT(TiGetBody((Tile *)tp->ti_client) == CLIENTDEFAULT,
"DBResetTilePlaneSpecial");
freeMagic(tp->ti_client);
}
tp->ti_client = cdata;

View File

@ -552,10 +552,13 @@ typedef struct diag_info
} DiagInfo;
/* Where search functions need to return a Tile pointer and tile split */
/* information, use this structure. */
/* information, use this structure. Contains a pointer to its own */
/* structure type so that it may also be used to create a linked list */
/* of tiles including split side information. */
typedef struct tile_and_dinfo
{
struct tile_and_dinfo *tad_next;
Tile *tad_tile;
TileType tad_dinfo;
} TileAndDinfo;
@ -929,6 +932,7 @@ extern int DBArraySr();
extern bool DBNearestLabel();
extern int DBSrLabelLoc();
extern TileType DBTransformDiagonal();
extern bool DBTestNMInteract(Rect *rect1, TileType tt1, Tile *t2, TileType di2, bool overlap_only);
extern int dbcUnconnectFunc(Tile *tile, TileType dinfo, ClientData clientData); /* (notused) */
extern int dbSrConnectFunc(Tile *tile, TileType dinfo, ClientData clientData); /* (struct conSrArg *csa) */
extern int dbSrConnectStartFunc(Tile *tile, TileType dinfo, ClientData clientData); /* cb_database_srpaintarea_t (Tile **pTile) */
@ -982,7 +986,6 @@ extern void DBResetTilePlaneSpecial();
extern void DBNewYank();
extern int DBSrPaintClient();
extern int DBSrConnect();
extern int DBSrConnectOnePlane();
extern char *dbFgets();
extern void DBAdjustLabelsNew();
extern bool DBScaleValue();

View File

@ -558,6 +558,7 @@ extBasic(def, outFile)
/* Clean up */
if (coupleInitialized)
extCapHashKill(&extCoupleHash);
ExtFreeLabRegions((LabRegion *) transList);
return (nodeList);
}
@ -906,6 +907,15 @@ extMakeNodeNumPrint(buf, lreg)
subsName = extSubsName(lreg);
if (subsName != NULL)
strcpy(buf, subsName);
else if (lreg->lreg_type & TT_SIDE)
/* Need to differentiate tiles with the type on the right
* side, because otherwise if there is a valid type on the
* left side, it will have the same generated node name.
*/
sprintf(buf, "%s_%s%d_%s%dx#",
DBPlaneShortName(plane),
(p->p_x < 0) ? "n": "", abs(p->p_x),
(p->p_y < 0) ? "n": "", abs(p->p_y));
else
sprintf(buf, "%s_%s%d_%s%d#",
DBPlaneShortName(plane),
@ -2130,9 +2140,9 @@ extTransFindTermArea(tile, dinfo, eapd)
TileType dinfo;
ExtAreaPerimData *eapd;
{
int extTermAPFunc(); /* Forward declaration */
void extTermAPFunc(); /* Forward declaration */
DBSrConnectOnePlane(tile, dinfo, DBConnectTbl, extTermAPFunc, (ClientData)eapd);
extEnumTerminal(tile, dinfo, DBConnectTbl, extTermAPFunc, (ClientData)eapd);
return 1;
}
@ -3599,14 +3609,13 @@ extAddSharedDevice(eapd, node)
* ----------------------------------------------------------------------------
*/
int
extTermAPFunc(tile, dinfo, pNum, eapd)
void
extTermAPFunc(tile, dinfo, eapd)
Tile *tile; /* Tile extending a device terminal */
TileType dinfo; /* Split tile information */
int pNum; /* Plane of tile (unused, set to -1) */
ExtAreaPerimData *eapd; /* Area and perimeter totals for terminal */
{
TileType type;
TileType type, tpdi;
Tile *tp;
Rect r;
@ -3628,13 +3637,14 @@ extTermAPFunc(tile, dinfo, pNum, eapd)
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
{
type = TiGetBottomType(tp);
tpdi = SplitDirection(tp) ? (TileType)0 : (TileType)TT_SIDE;
if (TTMaskHasType(&eapd->eapd_mask, type))
{
eapd->eapd_perim += MIN(RIGHT(tile), RIGHT(tp)) -
MAX(LEFT(tile), LEFT(tp));
if (TTMaskHasType(eapd->eapd_gatemask, type))
if (TiGetClientPTR(tp) != eapd->eapd_gatenode)
extAddSharedDevice(eapd, (NodeRegion *)TiGetClientPTR(tp));
if ((NodeRegion *)ExtGetRegion(tp, tpdi) != eapd->eapd_gatenode)
extAddSharedDevice(eapd, (NodeRegion *)ExtGetRegion(tp,tpdi));
}
}
@ -3642,13 +3652,14 @@ extTermAPFunc(tile, dinfo, pNum, eapd)
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
{
type = TiGetTopType(tp);
tpdi = SplitDirection(tp) ? (TileType)TT_SIDE : (TileType)0;
if (TTMaskHasType(&eapd->eapd_mask, type))
{
eapd->eapd_perim += MIN(RIGHT(tile), RIGHT(tp)) -
MAX(LEFT(tile), LEFT(tp));
if (TTMaskHasType(eapd->eapd_gatemask, type))
if (TiGetClientPTR(tp) != eapd->eapd_gatenode)
extAddSharedDevice(eapd, (NodeRegion *)TiGetClientPTR(tp));
if ((NodeRegion *)ExtGetRegion(tp, tpdi) != eapd->eapd_gatenode)
extAddSharedDevice(eapd, (NodeRegion *)ExtGetRegion(tp,tpdi));
}
}
@ -3656,13 +3667,14 @@ extTermAPFunc(tile, dinfo, pNum, eapd)
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
{
type = TiGetRightType(tp);
tpdi = (TileType)TT_SIDE;
if (TTMaskHasType(&eapd->eapd_mask, type))
{
eapd->eapd_perim += MIN(TOP(tile), TOP(tp)) -
MAX(BOTTOM(tile), BOTTOM(tp));
if (TTMaskHasType(eapd->eapd_gatemask, type))
if (TiGetClientPTR(tp) != eapd->eapd_gatenode)
extAddSharedDevice(eapd, (NodeRegion *)TiGetClientPTR(tp));
if ((NodeRegion *)ExtGetRegion(tp, tpdi) != eapd->eapd_gatenode)
extAddSharedDevice(eapd, (NodeRegion *)ExtGetRegion(tp,tpdi));
}
}
@ -3670,17 +3682,16 @@ extTermAPFunc(tile, dinfo, pNum, eapd)
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
{
type = TiGetLeftType(tp);
tpdi = (TileType)0;
if (TTMaskHasType(&eapd->eapd_mask, type))
{
eapd->eapd_perim += MIN(TOP(tile), TOP(tp)) -
MAX(BOTTOM(tile), BOTTOM(tp));
if (TTMaskHasType(eapd->eapd_gatemask, type))
if (TiGetClientPTR(tp) != eapd->eapd_gatenode)
extAddSharedDevice(eapd, (NodeRegion *)TiGetClientPTR(tp));
if ((NodeRegion *)ExtGetRegion(tp, tpdi) != eapd->eapd_gatenode)
extAddSharedDevice(eapd, (NodeRegion *)ExtGetRegion(tp,tpdi));
}
}
return 0;
}
/*
@ -3692,6 +3703,9 @@ extTermAPFunc(tile, dinfo, pNum, eapd)
* areas connected to the device (e.g., gate) and areas adjacent but
* not connected (e.g., source and drain).
*
* NOTE: The tile side bit for a split tile is determined by the boundary
* direction and so does not need to be passed as an argument.
*
* ----------------------------------------------------------------------------
*/
@ -3709,12 +3723,6 @@ extTransPerimFunc(bp)
Label *lab;
bool SDterm = FALSE;
/* NOTE: The tile side bit is not guaranteed to be correct
* when entering this routine. For split tiles, determine
* the correct type (type on left, right, bottom, or top)
* based on the recorded boundary direction.
*/
tile = bp->b_inside;
if (IsSplit(tile))
{
@ -3767,6 +3775,7 @@ extTransPerimFunc(bp)
{
toutside = TiGetTypeExact(bp->b_outside);
termNode = (NodeRegion *) ExtGetRegion(tile, (TileType)0);
dinfo = (TileType)0;
}
if (extTransRec.tr_devrec != NULL)
@ -3866,7 +3875,7 @@ extTransPerimFunc(bp)
eapd.eapd_gatenode = extTransRec.tr_gatenode;
eapd.eapd_shared = NULL;
DBSrConnectOnePlane(bp->b_outside, dinfo, DBConnectTbl,
extEnumTerminal(bp->b_outside, dinfo, DBConnectTbl,
extTermAPFunc, (ClientData)&eapd);
shared = 1;
@ -4485,17 +4494,28 @@ ExtSetRegion(Tile *tile,
{
if ((TiGetLeftType(tile) != TT_SPACE) && (TiGetRightType(tile) != TT_SPACE))
{
/* Tile is a split tile with something that is not space on both sides */
if (clientdata == CLIENTDEFAULT)
/* Tile is a split tile with something that is not space on both sides
* ti_client should not have any value other than CLIENTDEFAULT,
* VISITPENDING, or a split region structure.
*/
if ((clientdata == VISITPENDING) || (clientdata == CLIENTDEFAULT))
{
/* First time visit: tile requires an ExtSplitRegion structure */
csr = (ExtSplitRegion *)mallocMagic(sizeof(ExtSplitRegion));
TiSetClientPTR(tile, csr);
csr->reg_right = CLIENTDEFAULT;
csr->reg_left = CLIENTDEFAULT;
/* Note that "reg_guard" is in the first position, and setting
* it to CLIENTDEFAULT guards against accidentally mistakening
* a region pointer for a split region (see assertion, below).
*/
csr->reg_guard = CLIENTDEFAULT;
csr->reg_right = CD2PTR(clientdata);
csr->reg_left = CD2PTR(clientdata);
}
else
{
csr = (ExtSplitRegion *)CD2PTR(clientdata);
ASSERT(csr->reg_guard == CLIENTDEFAULT, "ExtSetRegion");
}
/* Set the region for the specified side of the tile */
if (dinfo & TT_SIDE)
@ -4542,19 +4562,27 @@ ExtResetRegion(Tile *tile,
if ((TiGetLeftType(tile) != TT_SPACE) && (TiGetRightType(tile) != TT_SPACE))
{
/* Tile is a split tile with something that is not space on both sides */
ExtSplitRegion *esr;
if (TiGetClient(tile) == CLIENTDEFAULT) return;
esr = (ExtSplitRegion *)TiGetClientPTR(tile);
if (dinfo & TT_SIDE)
esr->reg_right = CLIENTDEFAULT;
else
esr->reg_left = CLIENTDEFAULT;
ExtSplitRegion *esr = (ExtSplitRegion *)TiGetClientPTR(tile);;
ASSERT(PTR2CD(esr) != VISITPENDING, "ExtResetRegion");
if (PTR2CD(esr) == CLIENTDEFAULT) return; /* already reset */
/* ti_client should only ever be CLIENTDEFAULT, VISITPENDING, or a split
* region structure.
*/
if (PTR2CD(esr) != VISITPENDING)
{
if (dinfo & TT_SIDE)
esr->reg_right = CLIENTDEFAULT;
else
esr->reg_left = CLIENTDEFAULT;
if ((esr->reg_right == CLIENTDEFAULT) && (esr->reg_left == CLIENTDEFAULT))
freeMagic((char *)esr);
else
return;
if ((esr->reg_right == CLIENTDEFAULT) && (esr->reg_left == CLIENTDEFAULT))
freeMagic((char *)esr);
else
return;
}
}
}
/* In all other cases, just set the ClientData of the tile to value CLIENTDEFAULT */
@ -4813,6 +4841,7 @@ extFindNodes(def, clipArea, subonly)
if (extNodeStack == (Stack *) NULL)
extNodeStack = StackNew(64);
arg.fra_uninit = CLIENTDEFAULT;
arg.fra_def = def;
arg.fra_region = (ExtRegion *) NULL;
@ -4963,7 +4992,8 @@ extSubsFunc(tile, dinfo, arg)
smask = &ExtCurStyle->exts_globSubstrateShieldTypes;
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
if (TTMaskIntersect(&DBPlaneTypes[pNum], smask))
if (DBSrPaintArea((Tile *)NULL, arg->fra_def->cd_planes[pNum],
if (DBSrPaintNMArea((Tile *)NULL, arg->fra_def->cd_planes[pNum],
TiGetTypeExact(tile) | dinfo,
&tileArea, smask, extSubsFunc3, (ClientData)NULL) != 0)
return (0);
@ -4993,7 +5023,8 @@ extSubsFunc2(tile, dinfo, arg)
smask = &ExtCurStyle->exts_globSubstrateShieldTypes;
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
if (TTMaskIntersect(&DBPlaneTypes[pNum], smask))
if (DBSrPaintArea((Tile *) NULL, arg->fra_def->cd_planes[pNum],
if (DBSrPaintNMArea((Tile *) NULL, arg->fra_def->cd_planes[pNum],
TiGetTypeExact(tile) | dinfo,
&tileArea, smask, extSubsFunc3, (ClientData)NULL) != 0)
/* Keep the search going, as there may be other tiles to check */
return (0);
@ -5207,12 +5238,6 @@ topside:
{
PUSHTILEBOTTOM(tp, tilePlaneNum);
}
else if ((NodeRegion *)tireg != reg && TTMaskHasType(mask, t))
{
/* Count split tile twice, once for each node it belongs to. */
ExtResetRegion(tp, tpdinfo);
PUSHTILEBOTTOM(tp, tilePlaneNum);
}
}
else
{
@ -5263,12 +5288,6 @@ leftside:
{
PUSHTILERIGHT(tp, tilePlaneNum);
}
else if ((NodeRegion *)tireg != reg && TTMaskHasType(mask, t))
{
/* Count split tile twice, once for each node it belongs to. */
ExtResetRegion(tp, tpdinfo);
PUSHTILERIGHT(tp, tilePlaneNum);
}
}
else
{
@ -5320,12 +5339,6 @@ bottomside:
{
PUSHTILETOP(tp, tilePlaneNum);
}
else if ((NodeRegion *)tireg != reg && TTMaskHasType(mask, t))
{
/* Count split tile twice, once for each node it belongs to. */
ExtResetRegion(tp, tpdinfo);
PUSHTILETOP(tp, tilePlaneNum);
}
}
else
{
@ -5376,12 +5389,6 @@ rightside:
{
PUSHTILELEFT(tp, tilePlaneNum);
}
else if ((NodeRegion *)tireg != reg && TTMaskHasType(mask, t))
{
/* Count split tile twice, once for each node it belongs to */
ExtResetRegion(tp, tpdinfo);
PUSHTILELEFT(tp, tilePlaneNum);
}
}
else
{
@ -5478,8 +5485,8 @@ donesides:
Rect biggerArea;
bool is_split = IsSplit(tile);
extNbrUn = CLIENTDEFAULT;
TITORECT(tile, &pla.area);
pla.uninit = arg->fra_uninit;
GEO_EXPAND(&pla.area, 1, &biggerArea);
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
if ((pNum != tilePlaneNum) && PlaneMaskHasPlane(pMask, pNum))

View File

@ -60,13 +60,68 @@ int extHierConnectFunc2();
int extHierConnectFunc3();
Node *extHierNewNode();
/*----------------------------------------------------------------------*/
/* extHierSubShieldFunc -- */
/* */
/* Simple callback function for extHierSubstrate() that halts the */
/* search if any substrate shield type is found in the search area */
/* */
/*----------------------------------------------------------------------*/
/*
*----------------------------------------------------------------------
*
* extTestNMInteract --
*
* Determine if two tiles overlap, including split tiles. Since
* this is a much more complicated check than the simple overlap
* of two rectangular tiles, it is assumed that at least tile t1
* is a split tile, and does not check for simple rectangular
* overlap. The insideness test is the same used by
* DBSrPaintNMArea(), but in the context of extHierConnectFunc,
* the two tiles are already known, so just run the equations.
* Because this test is for electrical connectivity, touching
* shapes are equivalent to overlapping shapes.
*
* The information about which side of a triangular tile is to
* be checked for overlap is in the "dinfo" argument corresponding
* to the tile. If the tile is not a split tile, then "dinfo" is
* ignored.
*
* Tile t1 is always a split tile. Tile t2 may be a simple Manhattan
* tile, in which case the possibility that t2 has "infinite" width
* or height must be considered.
*
* Results:
* TRUE if the tiles overlap or touch, FALSE if not.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
bool extTestNMInteract(Tile *t1, TileType di1, Tile *t2, TileType di2)
{
Rect rect1;
TileType tt1;
/* Turn the first tile into a Rect and a TileType containing
* the information about both diagonal and split side, and
* then call the function DBTestNMInteract() which is used by
* DBSrPaintNMArea() to determine interaction between non-
* Manhattan areas. Note that DBTestNMInteract() is called
* with the overlap_only flag set to FALSE because this should
* test for shapes either overlapping *or* touching.
*/
TiToRect(t1, &rect1);
tt1 = TiGetTypeExact(t1) | di1;
return DBTestNMInteract(&rect1, tt1, t2, di2, FALSE);
}
/*
*----------------------------------------------------------------------
* extHierSubShieldFunc --
*
* Simple callback function for extHierSubstrate() that halts the
* search if any substrate shield type is found in the search area
*
*----------------------------------------------------------------------
*/
int
extHierSubShieldFunc(tile, dinfo, clientdata)
@ -77,19 +132,21 @@ extHierSubShieldFunc(tile, dinfo, clientdata)
return 1;
}
/*----------------------------------------------------------------------*/
/* extHierSubstrate -- */
/* */
/* Find the substrate node of a child cell and make a connection */
/* between parent and child substrates. If either of the */
/* substrate nodes is already in the hash table, then the table */
/* will be updated as necessary. */
/* */
/* This function also determines if a child cell's substrate is */
/* isolated by a substrate shield type, in which case no merge is */
/* done. */
/* */
/*----------------------------------------------------------------------*/
/*
*----------------------------------------------------------------------
* extHierSubstrate --
*
* Find the substrate node of a child cell and make a connection
* between parent and child substrates. If either of the
* substrate nodes is already in the hash table, then the table
* will be updated as necessary.
*
* This function also determines if a child cell's substrate is
* isolated by a substrate shield type, in which case no merge is
* done.
*
*----------------------------------------------------------------------
*/
void
extHierSubstrate(ha, use, x, y)
@ -504,7 +561,22 @@ extHierConnectFunc2(cum, dinfo, ha)
/* If the tiles don't even touch, they don't connect */
if (r.r_xtop < r.r_xbot || r.r_ytop < r.r_ybot
|| (r.r_xtop == r.r_xbot && r.r_ytop == r.r_ybot))
return (0);
return 0;
/* If either tile is a split tile, then check if the areas of
* interest overlap. The first argument to extTestNMInteract()
* must be a split tile.
*/
if (IsSplit(cum))
{
if (!extTestNMInteract(cum, dinfo, ha->hierOneTile, ha->hierType))
return 0;
}
else if (IsSplit(ha->hierOneTile))
{
if (!extTestNMInteract(ha->hierOneTile, ha->hierType, cum, dinfo))
return 0;
}
/*
* Only make a connection if the types of 'ha->hierOneTile' and 'cum'
@ -524,8 +596,8 @@ extHierConnectFunc2(cum, dinfo, ha)
nn = (NodeName *) HashGetValue(he);
node1 = nn ? nn->nn_node : extHierNewNode(he);
name2 = (*ha->ha_nodename)(ha->hierOneTile, ha->hierType, ha->hierPNum, extHierOneFlat,
ha, TRUE);
name2 = (*ha->ha_nodename)(ha->hierOneTile, ha->hierType, ha->hierPNum,
extHierOneFlat, ha, TRUE);
he = HashFind(table, name2);
nn = (NodeName *) HashGetValue(he);
node2 = nn ? nn->nn_node : extHierNewNode(he);

View File

@ -117,9 +117,12 @@ ExtFindNeighbors(tile, dinfo, tilePlaneNum, arg)
* been visited in the meantime. If it's still unvisited,
* visit it and process its neighbors.
*/
if (ExtGetRegion(tile, dinfo) == arg->fra_region);
if (ExtGetRegion(tile, dinfo) == arg->fra_region)
continue;
ExtSetRegion(tile, dinfo, arg->fra_region);
tilesfound++;
if (DebugIsSet(extDebugID, extDebNeighbor))
extShowTile(tile, "neighbor", 1);
@ -134,7 +137,6 @@ topside:
{
t = SplitBottomType(tp);
tpdinfo = SplitDirection(tp) ? (TileType)0 : (TileType)TT_SIDE;
// if (TiGetClientPTR(tp) != arg->fra_region && TTMaskHasType(mask, t))
if (ExtGetRegion(tp, tpdinfo) == CD2PTR(extNbrUn) && TTMaskHasType(mask, t))
{
PUSHTILEBOTTOM(tp, tilePlaneNum);
@ -158,7 +160,6 @@ leftside:
if (IsSplit(tp))
{
t = SplitRightType(tp);
// if (TiGetClientPTR(tp) != arg->fra_region && TTMaskHasType(mask, t))
if (ExtGetRegion(tp, (TileType)TT_SIDE) == CD2PTR(extNbrUn)
&& TTMaskHasType(mask, t))
{
@ -185,7 +186,6 @@ bottomside:
{
t = SplitTopType(tp);
tpdinfo = SplitDirection(tp) ? (TileType)TT_SIDE : (TileType)0;
// if (TiGetClientPTR(tp) != arg->fra_region && TTMaskHasType(mask, t))
if (ExtGetRegion(tp, tpdinfo) == CD2PTR(extNbrUn) && TTMaskHasType(mask, t))
{
PUSHTILETOP(tp, tilePlaneNum);
@ -209,7 +209,6 @@ rightside:
if (IsSplit(tp))
{
t = SplitLeftType(tp);
// if (TiGetClientPTR(tp) != arg->fra_region && TTMaskHasType(mask, t))
if (ExtGetRegion(tp, (TileType)0) == CD2PTR(extNbrUn)
&& TTMaskHasType(mask, t))
{
@ -232,6 +231,11 @@ donesides:
if ((*arg->fra_each)(tile, dinfo, tilePlaneNum, arg))
goto fail;
/* Use tilePlaneNum value -1 to force ExtFindNeighbors to stay
* on a single plane.
*/
if (tilePlaneNum < 0) continue;
/* If this is a contact, visit all the other planes */
if (DBIsContact(type))
{
@ -322,6 +326,7 @@ donesides:
*/
if ((pMask = DBAllConnPlanes[type]))
{
pla.uninit = extNbrUn;
TITORECT(tile, &pla.area);
GEO_EXPAND(&pla.area, 1, &biggerArea);
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
@ -334,7 +339,6 @@ donesides:
}
}
}
return tilesfound;
fail:
@ -399,3 +403,228 @@ extNbrPushFunc(tile, dinfo, pla)
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* extEnumTerminal ---
*
* Search out an area belonging to a device terminal starting with a given
* tile, and running a callback function for each tile found. Note that
* this routine is called from inside extEnumTilePerim and so is already
* inside an extFindNeighbors() search function. The function must be
* careful not to modify regions, as the outer search function depends on
* them. Because a device terminal should be a compact area, it is okay
* to create a linked list of tiles and use the linked list to reset the
* regions at the end, rather than depending on the state of any tile's
* ClientData record.
*
* Results:
* None.
*
* Side effects:
* Whatever the callback function does. Specifically, changing tile
* ClientData records is *not* supposed to be a side effect of this
* function, and all ClientData modifications must be put back exactly
* as they were found.
*
* NOTE: This routine should be called only once for each device terminal.
* Once the terminal area and perimeter have been measured, it will not be
* called again.
*
* ----------------------------------------------------------------------------
*/
void
extEnumTerminal(Tile *tile, /* Starting tile for search */
TileType dinfo, /* Split tile information */
TileTypeBitMask *connect, /* Pointer to connection table */
void (*func)(), /* Callback function */
ClientData clientData) /* Client data for callback function */
{
ExtRegion *termreg;
TileAndDinfo *pendlist = NULL, *resetlist = NULL;
TileAndDinfo *curtad;
const TileTypeBitMask *connectMask;
Tile *tp, *t2;
TileType tpdi, t2di;
TileType loctype, checktype;
Rect tileArea;
/* The region attached to the first terminal tile will be the
* "uninitialized" value to check.
*/
termreg = ExtGetRegion(tile, dinfo);
/* Set the ClientData to VISITPENDING */
ExtSetRegion(tile, dinfo, (ExtRegion *)VISITPENDING);
/* Start the linked list with this file */
curtad = (TileAndDinfo *)mallocMagic(sizeof(TileAndDinfo));
curtad->tad_tile = tile;
curtad->tad_dinfo = dinfo;
curtad->tad_next = NULL;
pendlist = curtad;
/* Yet another boundary search routine. Just done with a linked list
* and not a stack because it's expected to search only a handful of
* tiles.
*/
while (pendlist != NULL)
{
tp = pendlist->tad_tile;
tpdi = pendlist->tad_dinfo;
TiToRect(tp, &tileArea);
/* Call the client function. The function has no return value. */
(*func)(tp, tpdi, clientData);
/* Move this tile entry to reset list */
curtad = pendlist;
pendlist = pendlist->tad_next;
curtad->tad_next = resetlist;
resetlist = curtad;
/* Search all sides of the tile for other tiles having the same
* terminal node (same region in the ClientData record),
* and add them to the linked list. This code is largely copied
* from dbSrConnectFunc(). Note that the connect table is used
* because the device's gate node may have the same region but
* is not part of the terminal.
*/
if (IsSplit(tp))
{
if (tpdi & TT_SIDE)
loctype = SplitRightType(tp);
else
loctype = SplitLeftType(tp);
}
else
loctype = TiGetTypeExact(tp);
connectMask = &connect[loctype];
/* Left side */
if (IsSplit(tp) && (tpdi & TT_SIDE)) goto termbottom;
for (t2 = BL(tp); BOTTOM(t2) < tileArea.r_ytop; t2 = RT(t2))
{
if (IsSplit(t2))
checktype = SplitRightType(t2);
else
checktype = TiGetTypeExact(t2);
if (TTMaskHasType(connectMask, checktype))
{
t2di = (TileType)TT_SIDE;
/* Tile must belong to the terminal node and not been visited */
if (ExtGetRegion(t2, t2di) != termreg) continue;
/* Add t2 to the linked list */
curtad = (TileAndDinfo *)mallocMagic(sizeof(TileAndDinfo));
curtad->tad_tile = t2;
curtad->tad_dinfo = t2di;
curtad->tad_next = pendlist;
pendlist = curtad;
/* Set the ClientData to VISITPENDING */
ExtSetRegion(t2, t2di, (ExtRegion *)VISITPENDING);
}
}
/* Bottom side */
termbottom:
if (IsSplit(tp) && ((!((tpdi & TT_SIDE) ? 1 : 0)) ^ SplitDirection(tp)))
goto termright;
for (t2 = LB(tp); LEFT(t2) < tileArea.r_xtop; t2 = TR(t2))
{
if (IsSplit(t2))
checktype = SplitTopType(t2);
else
checktype = TiGetTypeExact(t2);
if (TTMaskHasType(connectMask, checktype))
{
t2di = SplitDirection(t2) ? (TileType)TT_SIDE : (TileType)0;
/* Tile must belong to the terminal node and not been visited */
if (ExtGetRegion(t2, t2di) != termreg) continue;
/* Add t2 to the linked list */
curtad = (TileAndDinfo *)mallocMagic(sizeof(TileAndDinfo));
curtad->tad_tile = t2;
curtad->tad_dinfo = t2di;
curtad->tad_next = pendlist;
pendlist = curtad;
/* Set the ClientData to VISITPENDING */
ExtSetRegion(t2, t2di, (ExtRegion *)VISITPENDING);
}
}
/* Right side: */
termright:
if (IsSplit(tp) && !(tpdi & TT_SIDE)) goto termtop;
for (t2 = TR(tp); BOTTOM(t2) > tileArea.r_ybot; t2 = LB(t2))
{
if (IsSplit(t2))
checktype = SplitLeftType(t2);
else
checktype = TiGetTypeExact(t2);
if (TTMaskHasType(connectMask, checktype))
{
t2di = (TileType)0;
/* Tile must belong to the terminal node and not been visited */
if (ExtGetRegion(t2, t2di) != termreg) continue;
/* Add t2 to the linked list */
curtad = (TileAndDinfo *)mallocMagic(sizeof(TileAndDinfo));
curtad->tad_tile = t2;
curtad->tad_dinfo = t2di;
curtad->tad_next = pendlist;
pendlist = curtad;
/* Set the ClientData to VISITPENDING */
ExtSetRegion(t2, t2di, (ExtRegion *)VISITPENDING);
}
}
/* Top side */
termtop:
if (IsSplit(tp) && (((tpdi & TT_SIDE) ? 1 : 0) ^ SplitDirection(tp)))
goto termdone;
for (t2 = RT(tp); LEFT(t2) > tileArea.r_xbot; t2 = BL(t2))
{
if (IsSplit(t2))
checktype = SplitBottomType(t2);
else
checktype = TiGetTypeExact(t2);
if (TTMaskHasType(connectMask, checktype))
{
t2di = SplitDirection(t2) ? (TileType)0 : (TileType)TT_SIDE;
/* Tile must belong to the terminal node and not been visited */
if (ExtGetRegion(t2, t2di) != termreg) continue;
/* Add t2 to the linked list */
curtad = (TileAndDinfo *)mallocMagic(sizeof(TileAndDinfo));
curtad->tad_tile = t2;
curtad->tad_dinfo = t2di;
curtad->tad_next = pendlist;
pendlist = curtad;
/* Set the ClientData to VISITPENDING */
ExtSetRegion(t2, t2di, (ExtRegion *)VISITPENDING);
}
}
termdone:
/* (continue) */
}
/* Clean up---Put the ClientData entries in the tiles back to
* term reg and free up the linked list memory.
*/
while (resetlist != NULL)
{
curtad = resetlist->tad_next;
ExtSetRegion(resetlist->tad_tile, resetlist->tad_dinfo, termreg);
freeMagic(resetlist);
resetlist = curtad;
}
}

View File

@ -68,10 +68,10 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
* to each qualifying segment of the boundary.
*
* Note:
* The width/length calculation method is manhattan-only. So this
* routine is pseudo-manhattan. It computes the true non-manhattan
* perimeter, but calls the function on the perimeter tiles as if
* the whole tile is the transistor type.
* The width/length calculation method is manhattan-only, and will
* likely need correcting. This routine computes the true perimeter
* length and calls the callback function on the perimeter tiles of
* the correct tile type.
*
* Non-interruptible.
*
@ -113,70 +113,78 @@ extEnumTilePerim(
perimCorrect = width * width + height * height;
perimCorrect = (int)sqrt((double)perimCorrect);
}
sides = (dinfo & TT_SIDE) ? BD_RIGHT : BD_LEFT;
sides = (dinfo & TT_SIDE) ? BD_LEFT : BD_RIGHT;
sides |= (((dinfo & TT_SIDE) ? 1 : 0) == SplitDirection(tpIn)) ?
BD_TOP : BD_BOTTOM;
BD_BOTTOM : BD_TOP;
}
else
sides = 0;
/* Top */
b.b_segment.r_ybot = b.b_segment.r_ytop = TOP(tpIn);
b.b_direction = BD_TOP;
for (tpOut = RT(tpIn); RIGHT(tpOut) > LEFT(tpIn); tpOut = BL(tpOut))
if (!(sides & BD_TOP))
{
if (TTMaskHasType(&mask, TiGetBottomType(tpOut)))
b.b_segment.r_ybot = b.b_segment.r_ytop = TOP(tpIn);
b.b_direction = BD_TOP;
for (tpOut = RT(tpIn); RIGHT(tpOut) > LEFT(tpIn); tpOut = BL(tpOut))
{
b.b_segment.r_xbot = MAX(LEFT(tpIn), LEFT(tpOut));
b.b_segment.r_xtop = MIN(RIGHT(tpIn), RIGHT(tpOut));
b.b_outside = tpOut;
if (sides & BD_TOP) perimCorrect -= BoundaryLength(&b);
if (func) (*func)(&b, cdata);
if (TTMaskHasType(&mask, TiGetBottomType(tpOut)))
{
b.b_segment.r_xbot = MAX(LEFT(tpIn), LEFT(tpOut));
b.b_segment.r_xtop = MIN(RIGHT(tpIn), RIGHT(tpOut));
b.b_outside = tpOut;
if (func) (*func)(&b, cdata);
}
}
}
/* Bottom */
b.b_segment.r_ybot = b.b_segment.r_ytop = BOTTOM(tpIn);
b.b_direction = BD_BOTTOM;
for (tpOut = LB(tpIn); LEFT(tpOut) < RIGHT(tpIn); tpOut = TR(tpOut))
if (!(sides & BD_BOTTOM))
{
if (TTMaskHasType(&mask, TiGetTopType(tpOut)))
b.b_segment.r_ybot = b.b_segment.r_ytop = BOTTOM(tpIn);
b.b_direction = BD_BOTTOM;
for (tpOut = LB(tpIn); LEFT(tpOut) < RIGHT(tpIn); tpOut = TR(tpOut))
{
b.b_segment.r_xbot = MAX(LEFT(tpIn), LEFT(tpOut));
b.b_segment.r_xtop = MIN(RIGHT(tpIn), RIGHT(tpOut));
b.b_outside = tpOut;
if (sides & BD_BOTTOM) perimCorrect -= BoundaryLength(&b);
if (func) (*func)(&b, cdata);
if (TTMaskHasType(&mask, TiGetTopType(tpOut)))
{
b.b_segment.r_xbot = MAX(LEFT(tpIn), LEFT(tpOut));
b.b_segment.r_xtop = MIN(RIGHT(tpIn), RIGHT(tpOut));
b.b_outside = tpOut;
if (func) (*func)(&b, cdata);
}
}
}
/* Left */
b.b_segment.r_xbot = b.b_segment.r_xtop = LEFT(tpIn);
b.b_direction = BD_LEFT;
for (tpOut = BL(tpIn); BOTTOM(tpOut) < TOP(tpIn); tpOut = RT(tpOut))
if (!(sides & BD_LEFT))
{
if (TTMaskHasType(&mask, TiGetRightType(tpOut)))
b.b_segment.r_xbot = b.b_segment.r_xtop = LEFT(tpIn);
b.b_direction = BD_LEFT;
for (tpOut = BL(tpIn); BOTTOM(tpOut) < TOP(tpIn); tpOut = RT(tpOut))
{
b.b_segment.r_ybot = MAX(BOTTOM(tpIn), BOTTOM(tpOut));
b.b_segment.r_ytop = MIN(TOP(tpIn), TOP(tpOut));
b.b_outside = tpOut;
if (sides & BD_LEFT) perimCorrect -= BoundaryLength(&b);
if (func) (*func)(&b, cdata);
if (TTMaskHasType(&mask, TiGetRightType(tpOut)))
{
b.b_segment.r_ybot = MAX(BOTTOM(tpIn), BOTTOM(tpOut));
b.b_segment.r_ytop = MIN(TOP(tpIn), TOP(tpOut));
b.b_outside = tpOut;
if (func) (*func)(&b, cdata);
}
}
}
/* Right */
b.b_segment.r_xbot = b.b_segment.r_xtop = RIGHT(tpIn);
b.b_direction = BD_RIGHT;
for (tpOut = TR(tpIn); TOP(tpOut) > BOTTOM(tpIn); tpOut = LB(tpOut))
if (!(sides & BD_RIGHT))
{
if (TTMaskHasType(&mask, TiGetLeftType(tpOut)))
b.b_segment.r_xbot = b.b_segment.r_xtop = RIGHT(tpIn);
b.b_direction = BD_RIGHT;
for (tpOut = TR(tpIn); TOP(tpOut) > BOTTOM(tpIn); tpOut = LB(tpOut))
{
b.b_segment.r_ybot = MAX(BOTTOM(tpIn), BOTTOM(tpOut));
b.b_segment.r_ytop = MIN(TOP(tpIn), TOP(tpOut));
b.b_outside = tpOut;
if (sides & BD_RIGHT) perimCorrect -= BoundaryLength(&b);
if (func) (*func)(&b, cdata);
if (TTMaskHasType(&mask, TiGetLeftType(tpOut)))
{
b.b_segment.r_ybot = MAX(BOTTOM(tpIn), BOTTOM(tpOut));
b.b_segment.r_ytop = MIN(TOP(tpIn), TOP(tpOut));
b.b_outside = tpOut;
if (func) (*func)(&b, cdata);
}
}
}

View File

@ -72,6 +72,15 @@ ExtGetRegion(Tile *tp, /* Tile to get region record from */
else
{
esr = (ExtSplitRegion *)tp->ti_client;
/* If this tile has not been handled and no ExtSplitRegion has
* been created, then ti_client should be either CLIENTDEFAULT
* or VISITPENDING. It should not have any other values.
*/
if ((ClientData)esr == CLIENTDEFAULT)
return CD2PTR(CLIENTDEFAULT);
else if ((ClientData)esr == VISITPENDING)
return CD2PTR(VISITPENDING);
return (dinfo & TT_SIDE) ? esr->reg_right : esr->reg_left;
}
}

View File

@ -1100,7 +1100,7 @@ extSubtreeTileToNode(tp, dinfo, pNum, et, ha, doHard)
{
if (DBSrPaintNMArea((Tile *) NULL,
et->et_lookNames->cd_planes[pNum],
TiGetTypeExact(tp), &r, &DBAllButSpaceBits,
dinfo, &r, &DBAllButSpaceBits,
extConnFindFunc, (ClientData) &reg))
{
if (SigInterruptPending)

View File

@ -161,6 +161,8 @@ typedef struct reg
*/
typedef struct split_reg
{
ExtRegion *reg_guard; // Use this to guard against failure to
// identify a split region (temporary).
ExtRegion *reg_left; // Region belonging to tile left side
ExtRegion *reg_right; // Region belonging to tile right side
} ExtSplitRegion;
@ -953,12 +955,6 @@ extern ExtStyle *ExtCurStyle;
/* ------------------- Hierarchical node merging ---------------------- */
/*
* Table used to hold all merged nodes during hierarchical extraction.
* Used for duplicate suppression.
*/
extern HashTable extHierMergeTable;
/*
* Each hash entry in the above table points to a NodeName struct.
* Each NodeName points to the Node corresponding to that name.
@ -1002,7 +998,7 @@ extern ExtRegion *ExtGetRegion(Tile *tile, TileType dinfo);
/* time the tile is pushed and the time that it is popped. */
#define PUSHTILE(tp, di, pl) \
(tp)->ti_client = VISITPENDING; \
ExtSetRegion(tp, di, (ExtRegion *)VISITPENDING); \
STACKPUSH((ClientData)(pointertype)pl, extNodeStack); \
STACKPUSH((ClientData)(pointertype)di, extNodeStack); \
STACKPUSH((ClientData)(pointertype)tp, extNodeStack)
@ -1015,27 +1011,31 @@ extern ExtRegion *ExtGetRegion(Tile *tile, TileType dinfo);
/* Variations of "pushtile" to force a specific value on TT_SIDE */
#define PUSHTILEBOTTOM(tp, pl) \
(tp)->ti_client = VISITPENDING; \
{ \
TileType di = (SplitDirection(tp)) ? 0 : TT_SIDE; \
ExtSetRegion(tp, di, (ExtRegion *)VISITPENDING); \
STACKPUSH((ClientData)(pointertype)pl, extNodeStack); \
STACKPUSH((ClientData)(pointertype) \
((SplitDirection(tp)) ? 0 : TT_SIDE), extNodeStack) ;\
STACKPUSH((ClientData)(pointertype)tp, extNodeStack)
STACKPUSH((ClientData)(pointertype)di, extNodeStack); \
STACKPUSH((ClientData)(pointertype)tp, extNodeStack); \
}
#define PUSHTILETOP(tp, pl) \
(tp)->ti_client = VISITPENDING; \
{ \
TileType di = (SplitDirection(tp)) ? TT_SIDE : 0; \
ExtSetRegion(tp, di, (ExtRegion *)VISITPENDING); \
STACKPUSH((ClientData)(pointertype)pl, extNodeStack); \
STACKPUSH((ClientData)(pointertype) \
((SplitDirection(tp)) ? TT_SIDE : 0), extNodeStack) ;\
STACKPUSH((ClientData)(pointertype)tp, extNodeStack)
STACKPUSH((ClientData)(pointertype)di, extNodeStack); \
STACKPUSH((ClientData)(pointertype)tp, extNodeStack); \
}
#define PUSHTILELEFT(tp, pl) \
(tp)->ti_client = VISITPENDING; \
ExtSetRegion(tp, (TileType)0, (ExtRegion *)VISITPENDING); \
STACKPUSH((ClientData)(pointertype)(pl), extNodeStack); \
STACKPUSH((ClientData)(pointertype)0, extNodeStack); \
STACKPUSH((ClientData)(pointertype)tp, extNodeStack)
#define PUSHTILERIGHT(tp, pl) \
(tp)->ti_client = VISITPENDING; \
ExtSetRegion(tp, (TileType)TT_SIDE, (ExtRegion *)VISITPENDING); \
STACKPUSH((ClientData)(pointertype)pl, extNodeStack); \
STACKPUSH((ClientData)(pointertype)TT_SIDE, extNodeStack); \
STACKPUSH((ClientData)(pointertype)tp, extNodeStack)
@ -1117,6 +1117,10 @@ extern Plane *extCellFile();
extern int extInterAreaFunc();
extern int extTreeSrPaintArea();
extern int extMakeUnique();
extern void extEnumTerminal();
extern void extEnumTerminal(Tile *tile, TileType dinfo,
TileTypeBitMask *connect, void (*func)(), ClientData clientData);
/* ------------------ Connectivity table management ------------------- */

View File

@ -588,6 +588,7 @@ SimSrConnect(
*/
tad.tad_tile = NULL;
tad.tad_next = NULL; /* unused */
for (startPlane = PL_TECHDEPBASE; startPlane < DBNumPlanes; startPlane++)
{
if (DBSrPaintArea((Tile *) NULL,

View File

@ -736,12 +736,12 @@ SimGetNodeName(
/* check to see if this tile has been extracted before */
if (TiGetClient(tp) == CLIENTDEFAULT)
if (ExtGetRegion(tp, dinfo) == (ExtRegion *)CLIENTDEFAULT)
{
NodeSpec *ns;
ns = SimFindOneNode(sx, tp, dinfo);
if( ns->nd_what == ND_NAME )
if (ns->nd_what == ND_NAME)
{
SimSawAbortString = TRUE;
return ns->nd_name;
@ -750,7 +750,7 @@ SimGetNodeName(
}
else
{
nodeList = (NodeRegion *)TiGetClientPTR(tp);
nodeList = (NodeRegion *)ExtGetRegion(tp, dinfo);
}
/* generate the node name from the label region and the path name */