DIRECTORY
CD USING [Number],
CDBasics USING [ComposeTransform, Extend, Intersect, MapRect],
CDProperties USING [RegisterProperty],
Core USING [Properties],
CoreClasses USING [CellInstance, recordCellClass, RecordCellType, transistorCellClass, unspecifiedCellClass],
CoreGeometry USING [CellInstance, Decoration, EachInstanceProc, EnumerateGeometry, GetObject, GetTrans, Instance, Instances, Layer, Object, Rect],
CoreOps USING [CopyWire, CreateWires, GetCellTypeName, GetShortWireName, SetShortWireName],
CoreProperties USING [GetProp, propPrint, PropPrintProc, Props, PutProp, RegisterProperty, StoreProperties],
Drc,
DrcDebug USING [break, Debug, debug, dLog, PrintWire],
FS USING [StreamOpen],
IO USING [card, char, Close, Error, Flush, int, Put1, PutF, PutF1, PutFR, PutFR1, PutRope, refAny, rope, STREAM, time],
RefTab USING [Create, EachPairAction, Fetch, Insert, Pairs, Ref, SeqIndex],
Rope USING [ROPE, IsEmpty],
Saguaro USING [ExtractedTransistor, ExtractTransistor],
TNT USING [BlowTNT, InitTNT, SweepTNT, TNT, UpdateTNT],
ViewerIO USING [CreateViewerStreams],
ViewerTools USING [FindExistingViewer, Viewer];
Verification of Core Cells
CheckCell:
TYPE ~
PROC [self: CoreCell, state: State, actual: Wire, transf: Transf];
Design rule checks a Core cell.
Must remove existing error information and check the intenal geometry. It has to perform both the binding and the propagation of the binding, making sure the Core data structure is not altered.
CheckCoreCell: CheckCell ~
BEGIN
SELECT self.class
FROM
CoreClasses.recordCellClass => CheckRecord [self, state, actual, transf];
CoreClasses.transistorCellClass => CheckTransistor [self, state, actual, transf];
CoreClasses.unspecifiedCellClass => ERROR;
ENDCASE => ERROR
END; -- CheckCoreCell
CheckRecord: CheckCell ~
BEGIN
cellData: CoreClasses.RecordCellType;
bindingTable: RefTab.Ref;
boundInternal: WireInstance;
propagatedActuals: WireSet; -- one wire per subcell
ownName: ROPE ~ CoreOps.GetCellTypeName [self];
GracefulAbort:
PROC [aborted:
BOOL ←
FALSE] ~
BEGIN
Places a message in the error Log.
IF aborted THEN eLog.PutF1 ["\n Verification of cell %g aborted.", IO.rope [ownName]]
END; -- GracefulAbort
IF (CoreProperties.GetProp [self.properties, doNotAnalyse]#NIL) OR ((NOT DrcDebug.debug) AND (CoreProperties.GetProp[self.properties, state.tech.checkedBy]#NIL)) THEN RETURN;
mLog.Put1 [IO.char ['.]];
IF DrcDebug.debug
THEN
BEGIN
bb: Rect ~ CellHull [self, transf, state];
DrcDebug.dLog.PutF [format: "\nChecking cell %l%g%l ",
v1: IO.rope ["e"],
v2: IF ownName = NIL THEN IO.refAny [self] ELSE IO.rope [ownName],
v3: IO.rope ["E"]];
DrcDebug.dLog.PutF [" with bounding box [%g, %g, %g, %g].\n", IO.int [bb.x1/state.tech.lambda], IO.int [bb.y1/state.tech.lambda], IO.int [bb.x2/state.tech.lambda], IO.int [bb.y2/state.tech.lambda]]
END;
IF state.abort^ THEN {GracefulAbort [state.abort^]; RETURN};
ClearErrors [self, state];
cellData ← NARROW [self.data, CoreClasses.RecordCellType];
self.properties ← CoreProperties.PutProp [self.properties, state.tech.checkedBy, $DrcWasHere];
To use the connectivity informstion from the Core data structure, we have to pass down not the wires, but rather their instances. This implementation tries to be fast.
bindingTable ← CreateBindingTable [actual: actual, public: self.public];
boundInternal ← [cellData.internal, BindInternal [bindingTable, cellData.internal, state], transf];
IF debugBinding
THEN
BEGIN
DrcDebug.dLog.PutF1 ["Binding and propagating: %g. Binding table:\n", IO.rope [ownName]];
PrintBinding [bindingTable];
DrcDebug.dLog.PutF1 ["Bound internal of %g:\n", IO.rope [ownName]];
DrcDebug.PrintWire [boundInternal.global]
END;
The propagated actuals must be determined here once for all, because new actual wires will differ from call to call.
propagatedActuals ← NEW [WireSetRec[cellData.size]];
FOR sub:
NAT
IN [0 .. cellData.size)
DO
propagatedActuals[sub] ← [NIL, -- depends on cell class
PropagateBinding [state, bindingTable, cellData.instances[sub].actual],
ComposedTransf [transf, cellData.instances[sub], state]]
ENDLOOP;
FlushBindingTable [bindingTable];
The catechism states, that the recursion on the subcells has to take place at the end of the check among the internal of self and its subcells, in the procedure MaterialToCellSeparation. Nomen est omen, so I put the recursion step in here where it makes more sense to me. Furthermore the catechism states that the world is top-down, and that hence the recursion step is done at the end. Beside yielding a better program structure, this allows for more agressive (i.e. geometric) pruning.
FOR sub:
NAT
IN [0 .. cellData.size)
DO
subTransf: Transf ~ ComposedTransf [transf, cellData.instances[sub], state];
CheckCoreCell [self: cellData.instances[sub].type,
actual: propagatedActuals[sub].global,
transf: propagatedActuals[sub].transf,
state: state];
IF state.abort^ THEN {GracefulAbort [state.abort^]; RETURN};
ENDLOOP;
Check the internal.
IF debugBinding
THEN
BEGIN
DrcDebug.dLog.PutF1 ["Verifying: %g\nbound internal:\n", IO.rope [ownName]];
DrcDebug.PrintWire [boundInternal.global]
END;
WARNING: The order of the calls of the technology dependent procedures is important and may not be changed.
FOR i:
NAT
IN [0 .. cellData.internal.size)
DO
Since in this case the error will go into the cell itself, we produce cell relative coordinates by appropriately setting transf.
w1: WireInstance ~ [boundInternal.local[i], boundInternal.global[i], identity];
state.tech.verifyWire [self, w1.local, state];
FOR j:
NAT
IN [i .. cellData.internal.size)
DO
Although the separation rules do not have to hold for aequipotential pieces of material, we have to artificially check the geometry of each wire against itself in order to be able to verify the separation of cuts.
w2: WireInstance ~ [boundInternal.local[j], boundInternal.global[j], identity];
state.tech.verifyWirePair [self, w1, w2, state];
IF state.abort^ THEN {GracefulAbort [state.abort^]; RETURN};
ENDLOOP
ENDLOOP;
Check the separation between the internal of self and its subcells.
FOR sub:
NAT
IN [0 .. cellData.size)
DO
FOR i:
NAT
IN [0 .. cellData.internal.size)
DO
MaterialToCellSeparation [cell: cellData.instances[sub].type,
father: self, -- for error marking
cellWire: propagatedActuals[sub],
materialWire: [boundInternal.local[i], boundInternal.global[i], transf],
state: state];
IF state.abort^ THEN {GracefulAbort [state.abort^]; RETURN};
ENDLOOP
ENDLOOP;
Check the separation between the subcells of self.
IF useTNT THEN SweepTNT [state.nt];
FOR sub1:
NAT
IN [0 .. cellData.size)
DO
obj1: CdObj ~ CoreGeometry.GetObject [state.attributes, cellData.instances[sub1].type];
bloated1: Rect ~ CDBasics.Extend [CDBasics.MapRect [obj1.bbox, propagatedActuals[sub1].transf], state.tech.maxSeparation];
FOR sub2:
NAT
IN (sub1 .. cellData.size)
DO
obj2: CdObj ~ CoreGeometry.GetObject [state.attributes, cellData.instances[sub2].type];
IF CDBasics.Intersect [bloated1, CDBasics.MapRect [obj2.bbox, propagatedActuals[sub2].transf]] THEN LOOP; -- avoid polluting TNT
IF useTNT AND (state.nt.UpdateTNT [obj1, obj2, propagatedActuals[sub1].transf, propagatedActuals[sub2].transf, propagatedActuals[sub1].global, propagatedActuals[sub2].global].wasThere) THEN LOOP;
IF DrcDebug.debug
THEN
BEGIN
bb1: Rect ~ CellHull [cellData.instances[sub1].type, propagatedActuals[sub1].transf, state];
bb2: Rect ~ CellHull [cellData.instances[sub2].type, propagatedActuals[sub2].transf, state];
DrcDebug.dLog.PutF ["\nWill check the separation between the subcells %g with bounding box [%g, %g, %g, %g]", IO.rope [CoreOps.GetCellTypeName [cellData.instances[sub1].type]], IO.int [bb1.x1/state.tech.lambda], IO.int [bb1.y1/state.tech.lambda], IO.int [bb1.x2/state.tech.lambda], IO.int [bb1.y2/state.tech.lambda]];
DrcDebug.dLog.PutF [" and %g with bounding box [%g, %g, %g, %g].\n", IO.rope [CoreOps.GetCellTypeName [cellData.instances[sub2].type]], IO.int [bb2.x1/state.tech.lambda], IO.int [bb2.y1/state.tech.lambda], IO.int [bb2.x2/state.tech.lambda], IO.int [bb2.y2/state.tech.lambda]]
END;
CellToCellSeparation [state: state, father: self,
cell1: cellData.instances[sub1].type,
cell2: cellData.instances[sub2].type,
wire1: propagatedActuals[sub1],
wire2: propagatedActuals[sub2]];
IF state.abort^ THEN {GracefulAbort [state.abort^]; RETURN}
ENDLOOP
ENDLOOP
END; -- CheckRecord
CheckTransistor: CheckCell ~
BEGIN
[self: CoreCell, state: State, actual: Wire, transf: Transf];
Transistors are atomic ChipNDale objects and are supposed to be correct by construction.
e: Saguaro.ExtractedTransistor ~ Saguaro.ExtractTransistor;
DoNotCheck [self, state, actual, transf]
END; -- CheckTransistor
DoNotCheck: CheckCell ~
BEGIN
[self: CoreCell, state: State, actual: Wire, transf: Transf];
(self.class = CoreClasses.unspecifiedCellClass) OR (CoreProperties.GetProp [self.properties, doNotAnalyse]#NIL);
self.properties ← CoreProperties.PutProp [self.properties, state.tech.checkedBy, $DrcWasHere]
END; -- DoNotCheck
Separation and Width Check Procedures
MaterialToCellProc:
TYPE ~
PROC [cell, father: CoreCell, cellWire, materialWire: WireInstance, state: State];
Checks a rectangle of material against all rectangles of material in a cell. It has to perform both the binding and the propagation of the binding, because the structure of the internal depends on the cell class.
CellToCellProc:
TYPE ~
PROC [cell1, cell2, father: CoreCell, wire1, wire2: WireInstance, state: State];
Checks all rectangles of material in a cell against those in another cell. It has to perform both the binding and the propagation of the binding, because the structure of the internal depends on the cell class.
MaterialToCellSeparation: MaterialToCellProc ~
BEGIN
For convenience.
SELECT cell.class
FROM
CoreClasses.recordCellClass => MaterialToRecordCellSeparation [cell, father, cellWire, materialWire, state];
CoreClasses.transistorCellClass => MaterialToTransistorSeparation [cell, father, cellWire, materialWire, state];
CoreClasses.unspecifiedCellClass => MaterialToUnspecifiedSeparation [cell, father, cellWire, materialWire, state];
ENDCASE => ERROR
END; -- MaterialToCellSeparation
MaterialToTransistorSeparation: MaterialToCellProc ~
BEGIN
[cell, father: CoreCell, cellWire, materialWire: WireInstance, state: State]
wbb, tbb: Rect; -- bounding boxes
boundInternal: WireInstance;
atomicBoundInternal: WireSet;
Intersect:
PROC
RETURNS [
BOOL] ~
INLINE
BEGIN
RETURN [CDBasics.Intersect [CDBasics.Extend [tbb, state.tech.maxSeparation], wbb]]
END; -- Intersect
IF state.abort^ THEN RETURN;
IF (CoreProperties.GetProp [cell.properties, doNotAnalyse] # NIL) THEN RETURN;
Find the bounding box of wire and check whether it has a non-empty intersection with the internal wire of the cell.
wbb ← AtomicWireHull [materialWire, state];
tbb ← CellHull [cell, cellWire.transf, state];
IF (NOT Intersect []) THEN RETURN;
boundInternal ← [cell.public, BindTransistor [cell.public, cellWire.global, state], cellWire.transf];
atomicBoundInternal ← NEW [WireSetRec[cell.public.size]];
FOR i:
NAT
IN [0 .. cell.public.size)
DO
atomicBoundInternal[i] ← [boundInternal.local[i], boundInternal.global[i], cellWire.transf]
ENDLOOP;
Check each element of the transistor wire of the cell against each element of wire.
FOR i:
NAT
IN [0 .. cell.public.size)
DO
IF state.abort^ THEN RETURN;
state.tech.verifyWirePair [state: state, cell: father, w1: atomicBoundInternal[i], w2: materialWire]
ENDLOOP
END; -- MaterialToTransistorSeparation
MaterialToUnspecifiedSeparation: MaterialToCellProc ~
BEGIN
[cell, father: CoreCell, cellWire, materialWire: WireInstance, state: State]
ERROR
END; -- MaterialToUnspecifiedSeparation
MaterialToRecordCellSeparation: MaterialToCellProc ~
BEGIN
[cell, father: CoreCell, cellWire, materialWire: WireInstance, state: State]
wbb, cbb: Rect; -- bounding boxes
boundInternal: WireInstance;
propagatedActuals, atomicBoundInternal: WireSet;
bindingTable: RefTab.Ref;
cellData: CoreClasses.RecordCellType ← NARROW [cell.data];
Intersect:
PROC
RETURNS [
BOOL] ~
INLINE
BEGIN
RETURN [CDBasics.Intersect [CDBasics.Extend [cbb, state.tech.maxSeparation], wbb]]
END; -- Intersect
IF state.abort^ THEN RETURN;
IF (CoreProperties.GetProp [cell.properties, doNotAnalyse] # NIL) OR (cellData.internal.size = 0) THEN RETURN;
Find the bounding box of wire and check whether it has a non-empty intersection with the internal wire of the cell.
wbb ← AtomicWireHull [materialWire, state];
cbb ← CellHull [cell, cellWire.transf, state];
IF (NOT Intersect[]) THEN RETURN;
Check each element of the internal wire of the cell against each element of wire.
bindingTable ← CreateBindingTable [actual: cellWire.global, public: cell.public];
boundInternal ← [cellData.internal, BindInternal [bindingTable, cellData.internal, state], cellWire.transf];
atomicBoundInternal ← NEW [WireSetRec[cellData.internal.size]];
FOR i:
NAT
IN [0 .. cellData.internal.size)
DO
atomicBoundInternal[i] ← [boundInternal.local[i], boundInternal.global[i], cellWire.transf]
ENDLOOP;
FOR i:
NAT
IN [0 .. cellData.internal.size)
DO
IF state.abort^ THEN RETURN;
state.tech.verifyWirePair [state: state, cell: father, w1: atomicBoundInternal[i], w2: materialWire]
ENDLOOP;
The propagated actuals must be determined here once for all, because new actual wires will differ from call to call.
propagatedActuals ← NEW [WireSetRec[cellData.size]];
FOR sub:
NAT
IN [0 .. cellData.size)
DO
propagatedActuals[sub] ← [NIL, -- depends on cell class
PropagateBinding [state, bindingTable, cellData.instances[sub].actual],
ComposedTransf [cellWire.transf, cellData.instances[sub], state]]
ENDLOOP;
FlushBindingTable [bindingTable];
Check intersections between subcells of cell and wire.
FOR sub:
NAT
IN [0 .. cellData.size)
DO
subTransf: Transf ~ ComposedTransf [cellWire.transf, cellData.instances[sub], state];
IF state.abort^ THEN RETURN;
MaterialToCellSeparation [cell: cellData.instances[sub].type,
father: cell, -- for error marking
cellWire: propagatedActuals[sub],
materialWire: [boundInternal.local[sub], boundInternal.global[sub], cellWire.transf],
state: state]
ENDLOOP
END; -- MaterialToRecordCellSeparation
CellToCellSeparation: CellToCellProc ~
BEGIN
[cell1, cell2, father: CoreCell, wire1, wire2: WireInstance, state: State]
For convenience.
SELECT cell2.class
FROM
CoreClasses.unspecifiedCellClass => ERROR;
CoreClasses.recordCellClass => NULL; -- default case
CoreClasses.transistorCellClass =>
-- nasty case
IF cell1.class = CoreClasses.transistorCellClass
THEN
BEGIN
TransistorToTransistorSeparation [cell1, cell2, father, wire1, wire2, state];
RETURN
END
ELSE
BEGIN
-- swap
cell1Z: CoreCell ~ cell1; wire1Z: WireInstance ~ wire1;
cell1 ← cell2; cell2 ← cell1Z;
wire1 ← wire2; wire2 ← wire1Z
END;
ENDCASE => ERROR;
SELECT cell1.class
FROM
CoreClasses.recordCellClass => RecordCellToRecordCellSeparation [cell1, cell2, father, wire1, wire2, state];
CoreClasses.transistorCellClass => TransistorToRecordCellSeparation [cell1, cell2, father, wire1, wire2, state];
CoreClasses.unspecifiedCellClass => UnspecifiedToAnyClassSeparation [cell1, cell2, father, wire1, wire2, state];
ENDCASE => ERROR
END; -- CellToCellSeparation
TransistorToTransistorSeparation: CellToCellProc ~
BEGIN
[cell1, cell2, father: CoreCell, wire1, wire2: WireInstance, state: State]
cbb1, cbb2: Rect; -- bounding boxes
boundInternal1, boundInternal2: WireInstance;
atomicBoundInternal1, atomicBoundInternal2: WireSet;
Intersect:
PROC
RETURNS [
BOOL] ~
INLINE
BEGIN
RETURN [CDBasics.Intersect [CDBasics.Extend[cbb1,state.tech.maxSeparation], cbb2]]
END; -- Intersect
Preamble.
IF state.abort^ THEN RETURN;
IF (CoreProperties.GetProp [cell1.properties, doNotAnalyse]#NIL) OR (CoreProperties.GetProp [cell2.properties, doNotAnalyse]#NIL) THEN RETURN;
cbb1 ← CellHull [cell1, wire1.transf, state];
cbb2 ← CellHull [cell2, wire2.transf, state];
IF (NOT Intersect[]) THEN RETURN;
Check the separation between the internal of cell1 and cell2.
IF state.abort^ THEN RETURN;
boundInternal1 ← [cell1.public, BindTransistor [cell1.public, wire1.global, state], wire1.transf];
boundInternal2 ← [cell2.public, BindTransistor [cell2.public, wire2.global, state], wire2.transf];
atomicBoundInternal1 ← NEW [WireSetRec[boundInternal1.local.size]];
atomicBoundInternal2 ← NEW [WireSetRec[boundInternal2.local.size]];
FOR i:
NAT
IN [0 .. boundInternal1.local.size)
DO
atomicBoundInternal1[i] ← [boundInternal1.local[i], boundInternal1.global[i], wire1.transf]
ENDLOOP;
FOR i:
NAT
IN [0 .. boundInternal2.local.size)
DO
atomicBoundInternal2[i] ← [boundInternal2.local[i], boundInternal2.global[i], wire2.transf]
ENDLOOP;
FOR i:
NAT
IN [0 .. cell1.public.size)
DO
FOR j:
NAT
IN [0 .. cell2.public.size)
DO
IF state.abort^ THEN RETURN;
state.tech.verifyWirePair [state: state, cell: father, w1: atomicBoundInternal1[i], w2: atomicBoundInternal2[j]]
ENDLOOP
ENDLOOP
END; -- TransistorToTransistorSeparation
TransistorToRecordCellSeparation: CellToCellProc ~
BEGIN
[cell1, cell2, father: CoreCell, wire1, wire2: WireInstance, state: State]
cbb1, cbb2: Rect; -- bounding boxes
cellData2: CoreClasses.RecordCellType ← NARROW [cell2.data];
bindingTable2: RefTab.Ref;
boundInternal1, boundInternal2: WireInstance;
atomicBoundInternal1, atomicBoundInternal2, propagatedActuals2: WireSet;
Intersect:
PROC
RETURNS [
BOOL] ~
INLINE
BEGIN
RETURN [CDBasics.Intersect [CDBasics.Extend [cbb1, state.tech.maxSeparation], cbb2]]
END; -- Intersect
Preamble.
IF state.abort^ THEN RETURN;
IF (CoreProperties.GetProp [cell1.properties, doNotAnalyse]#
NIL)
OR (CoreProperties.GetProp [cell2.properties, doNotAnalyse]#
NIL)
THEN
RETURN;
IF DrcDebug.debug
THEN
BEGIN
ownName: ROPE ~ CoreOps.GetCellTypeName [cell1];
otherName: ROPE ~ CoreOps.GetCellTypeName [cell2];
DrcDebug.dLog.PutF [format: "Checking transistor %l%g%l vs. %g. ",
v1: IO.rope ["e"],
v2: IF (ownName = NIL) THEN IO.refAny [cell1] ELSE IO.rope [ownName],
v3: IO.rope ["E"],
v4: IF (otherName = NIL) THEN IO.refAny [cell2] ELSE IO.rope [otherName]]
END;
cbb1 ← CellHull [cell1, wire1.transf, state];
cbb2 ← CellHull [cell2, wire2.transf, state];
IF (NOT Intersect[]) THEN RETURN;
Check the separation between the internal of transistor and cell2.
IF state.abort^ THEN ERROR ABORTED;
boundInternal1 ← [cell1.public, BindTransistor [cell1.public, wire1.global, state], wire1.transf];
atomicBoundInternal1 ← NEW [WireSetRec[cell1.public.size]];
FOR i:
NAT
IN [0 .. cell1.public.size)
DO
atomicBoundInternal1[i] ← [boundInternal1.local[i], boundInternal1.global[i], wire1.transf]
ENDLOOP;
bindingTable2 ← CreateBindingTable [actual: wire2.global, public: cell2.public];
boundInternal2 ← [cellData2.internal, BindInternal [bindingTable2, cellData2.internal, state], wire2.transf];
atomicBoundInternal2 ← NEW [WireSetRec[cellData2.internal.size]];
FOR i:
NAT
IN [0 .. cellData2.internal.size)
DO
atomicBoundInternal2[i] ← [boundInternal2.local[i], boundInternal2.global[i], wire2.transf]
ENDLOOP;
propagatedActuals2 ← NEW [WireSetRec[cellData2.internal.size]];
FOR sub:
NAT
IN [0 .. cellData2.internal.size)
DO
propagatedActuals2[sub] ← [NIL, -- depends on cell class
PropagateBinding [state, bindingTable2, cellData2.instances[sub].actual],
ComposedTransf [wire2.transf, cellData2.instances[sub], state]]
ENDLOOP;
FlushBindingTable [bindingTable2];
FOR i:
NAT
IN [0 .. wire1.local.size)
DO
FOR j:
NAT
IN [0 .. wire2.local.size)
DO
IF state.abort^ THEN RETURN;
state.tech.verifyWirePair [state: state, cell: father, w1: atomicBoundInternal1[i], w2: atomicBoundInternal2[j]]
ENDLOOP
ENDLOOP;
Check intersections between subcells of transistor wires and cell2.
FOR i:
NAT
IN [0 .. wire1.local.size)
DO
FOR sub:
NAT
IN [0 .. cellData2.size)
DO
subTransf: Transf ~ ComposedTransf [wire2.transf, cellData2.instances[sub], state];
IF state.abort^ THEN RETURN;
MaterialToCellSeparation [cell: cellData2.instances[sub].type,
father: father, -- for error marking
cellWire: propagatedActuals2[sub],
materialWire: atomicBoundInternal1[i],
state: state]
ENDLOOP
ENDLOOP
END; -- TransistorToRecordCellSeparation
UnspecifiedToAnyClassSeparation: CellToCellProc ~
BEGIN
[cell1, cell2, father: CoreCell, wire1, wire2: WireInstance, state: State]
ERROR
END; -- UnspecifiedToAnyClassSeparation
RecordCellToRecordCellSeparation: CellToCellProc ~
BEGIN
[cell1, cell2, father: CoreCell, wire1, wire2: WireInstance, state: State]
cbb1, cbb2: Rect; -- bounding boxes
cellData1: CoreClasses.RecordCellType ← NARROW [cell1.data];
cellData2: CoreClasses.RecordCellType ← NARROW [cell2.data];
bindingTable1, bindingTable2: RefTab.Ref;
boundInternal1, boundInternal2: WireInstance;
atomicBoundInternal1, atomicBoundInternal2, propagatedActuals1, propagatedActuals2: WireSet;
Intersect:
PROC
RETURNS [
BOOL] ~
INLINE
BEGIN
RETURN [CDBasics.Intersect [CDBasics.Extend[cbb1,state.tech.maxSeparation], cbb2]]
END; -- Intersect
Preamble.
IF state.abort^ THEN RETURN;
IF (CoreProperties.GetProp [cell1.properties, doNotAnalyse]#NIL) OR (CoreProperties.GetProp [cell2.properties, doNotAnalyse]#NIL) THEN RETURN;
IF DrcDebug.debug
THEN
BEGIN
name1: ROPE ~ CoreOps.GetCellTypeName [cell1];
name2: ROPE ~ CoreOps.GetCellTypeName [cell2];
DrcDebug.dLog.PutF [format: "Checking record cell %l%g%l vs. %g.\n",
v1: IO.rope ["e"],
v2: IF name1.IsEmpty THEN IO.refAny [cell1] ELSE IO.rope [name1],
v3: IO.rope ["E"],
v4: IF name2.IsEmpty THEN IO.refAny [cell2] ELSE IO.rope [name2]]
END;
cbb1 ← CellHull [cell1, wire1.transf, state];
cbb2 ← CellHull [cell2, wire2.transf, state];
IF (NOT Intersect[]) THEN RETURN;
Check the separation between the internal of cell1 and cell2.
IF state.abort^ THEN RETURN;
bindingTable1 ← CreateBindingTable [actual: wire1.global, public: cell1.public];
bindingTable2 ← CreateBindingTable [actual: wire2.global, public: cell2.public];
boundInternal1 ← [cellData1.internal, BindInternal [bindingTable1, cellData1.internal, state], wire1.transf];
boundInternal2 ← [cellData2.internal, BindInternal [bindingTable2, cellData2.internal, state], wire2.transf];
atomicBoundInternal1 ← NEW [WireSetRec[boundInternal1.local.size]];
atomicBoundInternal2 ← NEW [WireSetRec[boundInternal2.local.size]];
FOR i:
NAT
IN [0 .. boundInternal1.local.size)
DO
atomicBoundInternal1[i] ← [boundInternal1.local[i], boundInternal1.global[i], wire1.transf]
ENDLOOP;
FOR i:
NAT
IN [0 .. boundInternal2.local.size)
DO
atomicBoundInternal2[i] ← [boundInternal2.local[i], boundInternal2.global[i], wire2.transf]
ENDLOOP;
propagatedActuals1 ← NEW [WireSetRec[cellData1.internal.size]];
FOR sub:
NAT
IN [0 .. cellData1.size)
DO
propagatedActuals2[sub] ← [NIL, -- depends on cell class
PropagateBinding [state, bindingTable1, cellData1.instances[sub].actual],
ComposedTransf [wire1.transf, cellData1.instances[sub], state]]
ENDLOOP;
propagatedActuals2 ← NEW [WireSetRec[cellData2.internal.size]];
FOR sub:
NAT
IN [0 .. cellData2.size)
DO
propagatedActuals2[sub] ← [NIL, -- depends on cell class
PropagateBinding [state, bindingTable2, cellData2.instances[sub].actual],
ComposedTransf [wire2.transf, cellData2.instances[sub], state]]
ENDLOOP;
FlushBindingTable [bindingTable1]; FlushBindingTable [bindingTable2];
FOR i:
NAT
IN [0 .. cellData1.internal.size)
DO
FOR j:
NAT
IN [0 .. cellData2.internal.size)
DO
state.tech.verifyWirePair [state: state, cell: father, w1: atomicBoundInternal1[i], w2: atomicBoundInternal2[j]]
ENDLOOP
ENDLOOP;
FOR sub:
NAT
IN [0 .. cellData2.size)
DO
FOR i:
NAT
IN [0 .. cellData1.internal.size)
DO
MaterialToCellSeparation [cell: cellData2.instances[sub].type,
father: father, -- for error marking
cellWire: propagatedActuals2[sub],
materialWire: atomicBoundInternal1[i],
state: state]
ENDLOOP
ENDLOOP;
FOR sub:
NAT
IN [0 .. cellData1.size)
DO
FOR i:
NAT
IN [0 .. cellData2.internal.size)
DO
MaterialToCellSeparation [cell: cellData1.instances[sub].type,
father: father, -- for error marking
cellWire: propagatedActuals1[sub],
materialWire: atomicBoundInternal2[i],
state: state]
ENDLOOP
ENDLOOP;
FOR sub1:
NAT
IN [0 .. cellData1.size)
DO
obj1: CdObj ~ CoreGeometry.GetObject [state.attributes, cellData1.instances[sub1].type];
bloated1: Rect ~ CDBasics.Extend [CDBasics.MapRect [obj1.bbox, propagatedActuals1[sub1].transf], state.tech.maxSeparation];
FOR sub2:
NAT
IN (sub1 .. cellData2.size)
DO
obj2: CdObj ~ CoreGeometry.GetObject [state.attributes, cellData2.instances[sub2].type];
IF CDBasics.Intersect [bloated1, CDBasics.MapRect [obj2.bbox, propagatedActuals2[sub2].transf]] THEN LOOP; -- avoid polluting TNT
IF useTNT AND (state.nt.UpdateTNT [obj1, obj2, propagatedActuals1[sub1].transf, propagatedActuals2[sub2].transf, propagatedActuals1[sub1].global, propagatedActuals2[sub2].global].wasThere) THEN LOOP;
CellToCellSeparation [state: state, father: father,
cell1: cellData1.instances[sub1].type,
cell2: cellData2.instances[sub2].type,
wire1: propagatedActuals1[sub1],
wire2: propagatedActuals2[sub2]]
ENDLOOP
ENDLOOP
END; -- RecordCellToRecordCellSeparation