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