<> <> <> <> <> <> <> <<... E tu, lenta ginestra, che di selve odorate queste campagne dispogliate adorni, anche tu presto alla cruel possanza soccomberai dal sotterraneo foco, che ritornando al loco gia noto, stendera l'avaro lembo su tue molli foreste. E piegherai sotto il fascio mortal non renitente il tuo capo innocente: ma non piegato insino allora indarno codardamente supplicando innanzi al futuro oppressor; ma non eretto con forsennato orgoglio inver le stelle, n e sul deserto, dove e la sede e i natali non per voler ma per fortuna avesti; ma piu saggia, ma tanto meno inferma dell'uom, quanto le frali tue stirpi non credesti o dal fato o da te fatte immortali.>> DIRECTORY CD USING [Number, Transformation], CDBasics USING [Extend, Intersect, Intersection, NonEmpty], CDBasicsInline USING [ComposeTransform, MapRect], CDProperties USING [GetObjectProp, RegisterProperty], Core USING [Properties], CoreClasses USING [CellInstance, recordCellClass, RecordCellType, transistorCellClass, unspecifiedCellClass], CoreGeometry USING [CellInstance, Decoration, EachInstanceProc, EnumerateGeometry, GetObject, GetTrans, HasGeometry, InlineBBox, Instance, Instances, Layer, Object], CoreOps USING [CopyWire, CreateWires, GetCellTypeName, GetShortWireName, SetShortWireName], CoreProperties USING [GetProp, propPrint, PropPrintProc, Props, PutProp, RegisterProperty, StoreProperties], Drc, DrcDebug USING [break, GeometryInWire, 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], Rope USING [Concat, Equal, IsEmpty, ROPE], SimpleMailer USING [SendMessage], TNT USING [BlowTNT, InitTNT, SweepTNT, TNT, UpdateTNT], UserCredentials USING [Get], ViewerIO USING [CreateViewerStreams], ViewerTools USING [FindExistingViewer, Viewer]; DrcImpl: CEDAR PROGRAM IMPORTS CDBasics, CDBasicsInline, CDProperties, CoreClasses, CoreGeometry, CoreOps, CoreProperties, DrcDebug, FS, IO, RefTab, Rope, SimpleMailer, TNT, UserCredentials, ViewerIO, ViewerTools EXPORTS Drc SHARES Drc ~ BEGIN OPEN Drc, TNT; <> <> debugBinding: BOOL _ FALSE; -- for debugging the binding only useTNT: BOOL ~ TRUE; -- for timing analysis only panic: SIGNAL ~ CODE; -- cannot communicate violations coreInconsistent: PUBLIC ERROR [reason: ROPE, torch: REF ANY] ~ CODE; coreMess: SIGNAL [reason: ROPE, torch: REF ANY] ~ CODE; -- clean up before issuing coreInconsistent isnotgbb: BOOL ~ NOT UserCredentials.Get[].name.Equal ["Beretta.pa", FALSE]; notify: BOOL ~ FALSE; <> mLog, eLog: IO.STREAM; -- messages and error log <> CdInsts: TYPE ~ CoreGeometry.Instances; CdObj: TYPE ~ CoreGeometry.Object; CoreInst: TYPE ~ CoreGeometry.CellInstance; FakeInst: TYPE ~ CoreGeometry.Instance; Layer: TYPE ~ CoreGeometry.Layer; ROPE: TYPE ~ Rope.ROPE; <> <> DRVkey: PUBLIC ATOM _ CoreProperties.RegisterProperty [$DrcError]; <> bbKey: ATOM _ CoreProperties.RegisterProperty [$DrcBB]; <> <> rectClass: ATOM ~ $Rect; pinClass: ATOM ~ $PinOb0; <> doNotAnalyse: ATOM ~ $DoNotDRC; <> identity: Transf; -- READONLY it is the default errorFeedbackCutOff: CARDINAL ~ 150; -- after this number of errors, a | is no longer displayed in the ChipNDale Terminal viewer (if it may be displayed at all). BoundingBox: TYPE ~ REF BoundingBoxRec; -- the wires of a set of cells BoundingBoxRec: TYPE ~ RECORD [bb: SEQUENCE size: NAT OF Rect]; WireSetList: TYPE ~ LIST OF WireSet _ NIL; Marks: TYPE ~ RECORD [cell: SEQUENCE size: NAT OF Rect]; <> CheckDesignRules: PUBLIC PROC [cell: CoreCell, external: Wire, tech: Tech, viaFlatness: BOOL _ FALSE, stopFlag: REF BOOL, lap: REF CARDINAL, currentCell: REF Rope.ROPE, layout: Layout] RETURNS [quantity: CARDINAL _ 0] ~ BEGIN <> ENABLE BEGIN IO.Error => IF ec = StreamClosed THEN BEGIN s: IO.STREAM; m: BOOL = (stream = mLog); IF m THEN StartLog [] ELSE DrcDebug.Debug []; s _ IF m THEN mLog ELSE DrcDebug.dLog; CONTINUE END; panic => GOTO paranoia END; state: State _ NEW [StateRec]; messy: BOOL _ FALSE; abortionCause, logMsg: ROPE; debugTorch: REF ANY; rootCellName: ROPE ~ CoreOps.GetCellTypeName [cell]; logFile: ROPE ~ "[]<>Temp>DRC>Genista.Log"; busted: ROPE ~ "\nDRC failed. Your Core data structure may be busted!"; eLog _ FS.StreamOpen [fileName: logFile, accessOptions: create, keep: 5, extendFileProc: NIL, remoteCheck: FALSE, wDir: NIL]; -- keep is 5 because of incremental use eLog.PutF ["Error log by Drc Genista. Root cell: %g, time: %g\n\n", IO.rope [rootCellName], IO.time []]; IF DrcDebug.debug THEN DrcDebug.dLog.PutF [format: "\n%g. cell: %l%g%l\n", v1: IO.time [], v2: IO.rope ["b"], v3: IF rootCellName = NIL THEN IO.refAny [cell] ELSE IO.rope [rootCellName], v4: IO.rope ["B"]]; state.viaFlatness _ viaFlatness; IF viaFlatness THEN mLog.PutRope ["Will verify via flatness.\n"]; state.abort _ IF stopFlag # NIL THEN stopFlag ELSE NEW [BOOL _ FALSE]; state.globalErrorCount _ lap; state.globalErrorCount^ _ 0; state.currentCell _ currentCell; state.currentCell^ _ rootCellName; IF useTNT THEN BEGIN state.nt _ InitTNT []; state.ttNt _ InitTNT []; state.ctNt _ InitTNT [] END; state.tech _ tech; IF (tech.maxSeparation = 0) OR (tech.maxSeparation = LAST [CD.Number]) THEN ERROR; state.attributes _ layout; <> [] _ CheckCoreCell [self: cell, state: state, actual: external, transf: identity ! coreMess => {messy _ TRUE; abortionCause _ reason; debugTorch _ torch; CONTINUE}]; eLog.Flush; mLog.Put1 [IO.char [':]]; IF (state.tech.verifyCell # NIL) THEN state.tech.verifyCell [cell: cell, state: state] ELSE mLog.PutRope ["\nWells and diffusion sex NOT fully verified."]; IF useTNT THEN BEGIN BlowTNT [state.nt]; BlowTNT [state.ttNt]; BlowTNT [state.ctNt] END; IF messy THEN BEGIN <> IF DrcDebug.debug THEN DrcDebug.break; cell.properties _ CoreProperties.PutProp [cell.properties, state.tech.checkedBy, NIL]; mLog.PutRope [busted]; eLog.PutRope [busted]; eLog.Close []; quantity _ LAST [CARDINAL]; IF isnotgbb THEN [] _ SimpleMailer.SendMessage [from: "Genista", to: LIST ["DAToolsImplementors^.PA"], subject: "Genista Aborted", body: IO.PutFR ["Root cell: %g\n%g\nAbortionCause:%g\nViolations so far:%g", IO.rope [rootCellName], IO.refAny [cell], IO.rope [abortionCause], IO.card [state.globalErrorCount^]]]; coreInconsistent [abortionCause, debugTorch] END; quantity _ state.globalErrorCount^; <> logMsg _ IF viaFlatness THEN "\nVia flatness verified.\n" ELSE "\nVia flatness NOT verified.\n"; eLog.PutF [format: "\nNumber of new design violations found: %l%g%l\n", v1: IO.rope ["b"], v2: IO.card [quantity], v3: IO.rope ["B"]]; mLog.PutRope [logMsg]; eLog.PutRope [logMsg]; IF (state.anathemas[0] + state.anathemas[1] + state.anathemas[2] # 0) THEN BEGIN logMsg _ "Religion of pairwise correctness at every level was broken but is forgiven (exponentially)\n"; mLog.PutRope [logMsg]; eLog.PutRope [logMsg]; IF (state.anathemas[0] # 0) THEN BEGIN logMsg _ IO.PutFR1 ["\tCell not correct in isolation but correct in context: %g\n", IO.card [state.anathemas[0]]]; mLog.PutRope [logMsg]; eLog.PutRope [logMsg] END; IF (state.anathemas[1] # 0) THEN BEGIN logMsg _ IO.PutFR1 ["\tRectangle pair not correct in isolation but correct in context: %g\n", IO.card [state.anathemas[1]]]; mLog.PutRope [logMsg]; eLog.PutRope [logMsg] END; IF (state.anathemas[2] # 0) THEN BEGIN logMsg _ IO.PutFR1 ["\tRectangle pair not permitted but allowed by technology: %g\n", IO.card [state.anathemas[2]]]; mLog.PutRope [logMsg]; eLog.PutRope [logMsg] END; IF (state.anathemas[3] # 0) THEN BEGIN logMsg _ IO.PutFR1 ["\tRule is an exception: %g\n", IO.card [state.anathemas[3]]]; mLog.PutRope [logMsg]; eLog.PutRope [logMsg] END END; logMsg _ IF state.abort^ THEN "\nDRC aborted."ELSE "\nDRC terminated normally."; eLog.PutRope [logMsg]; eLog.Close []; mLog.PutF1 ["\nViolations logged on %g\n", IO.rope [logFile]]; IF notify AND isnotgbb THEN [] _ SimpleMailer.SendMessage [from: "Genista", to: LIST ["Beretta.PA"], subject: "User Statistics", body: IO.PutFR ["Root cell: %g\n%g\nViolations:%g\nTermination: %g", IO.rope [rootCellName], IO.refAny [cell], IO.card [quantity], IO.rope [logMsg]]]; EXITS <> paranoia => -- cannot communicate with anybody {eLog.PutRope ["\nThis is paranoia."]; eLog.Close []} END; -- CheckDesignRules <> ComposedTransf: PROC [parent: Transf, child: CoreInst, state: State] RETURNS [Transf] ~ INLINE BEGIN <> RETURN [CDBasicsInline.ComposeTransform [CoreGeometry.GetTrans [state.attributes, child], parent]] END; -- ComposedTransf BloatedIntersection: PROC [r1, r2: Rect, e1, e2: CD.Number] RETURNS [Rect] ~ INLINE BEGIN <> RETURN [CDBasics.Intersection [CDBasics.Extend [r1, e1 / 2], CDBasics.Extend [r2, e2 / 2]]] END; -- BloatedIntersection <> CheckCell: TYPE ~ PROC [self: CoreCell, state: State, actual: Wire, transf: Transf] RETURNS [peek: WireSet _ NIL]; <> <> <> CheckCoreCell: CheckCell ~ BEGIN <<[self: CoreCell, state: State, actual: Wire, transf: Transf] RETURNS [peek: WireSet _ NIL]>> SELECT self.class FROM CoreClasses.recordCellClass => RETURN [CheckRecord [self, state, actual, transf]]; CoreClasses.transistorCellClass => RETURN [CheckTransistor [self, state, actual, transf]]; CoreClasses.unspecifiedCellClass => ERROR; ENDCASE => BEGIN WHILE (self.class # CoreClasses.recordCellClass) DO self _ self.class.recast [self] ENDLOOP; [] _ CheckRecord [self, state, actual, transf] END END; -- CheckCoreCell CheckRecord: CheckCell ~ BEGIN <<[self: CoreCell, state: State, actual: Wire, transf: Transf] RETURNS [peek: WireSet _ NIL]>> cellData: CoreClasses.RecordCellType; bindingTable: RefTab.Ref; boundInternal: WireInstance; propagatedActuals, atomicBoundInternal: WireSet; -- one wire per subcell ownName: ROPE _ CoreOps.GetCellTypeName [self]; bb: Rect ~ CellHull [self, transf, state]; subBB: BoundingBox; channelPeekList: WireSetList; GracefulAbort: PROC [aborted: BOOL _ FALSE] ~ BEGIN <> IF aborted THEN BEGIN eLog.PutF1 ["\n Verification of cell %g aborted.", IO.rope [ownName]]; self.properties _ CoreProperties.PutProp [self.properties, state.tech.checkedBy, NIL] END END; -- GracefulAbort IF (CDProperties.GetObjectProp [CoreGeometry.GetObject [state.attributes, self], doNotAnalyse]#NIL) OR ((NOT DrcDebug.debug) AND (CoreProperties.GetProp[self.properties, state.tech.checkedBy]#NIL)) THEN RETURN; mLog.Put1 [IO.char ['.]]; IF (ownName = NIL) THEN ownName _ IO.PutFR1 ["%g", IO.refAny [self]]; IF DrcDebug.debug THEN BEGIN DrcDebug.dLog.PutF [format: "\nChecking cell %l%g%l ", v1: IO.rope ["e"], v2: 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}; state.currentCell^ _ ownName; ClearErrors [self, state]; cellData _ NARROW [self.data, CoreClasses.RecordCellType]; self.properties _ CoreProperties.PutProp [self.properties, state.tech.checkedBy, $DrcWasHere]; <> bindingTable _ CreateBindingTable [actual: actual, public: self.public]; <> 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; boundInternal _ [cellData.internal, BindInternal [bindingTable, cellData.internal, state], transf]; atomicBoundInternal _ NEW [WireSetRec[boundInternal.local.size]]; FOR i: NAT IN [0 .. boundInternal.local.size) DO atomicBoundInternal[i] _ [boundInternal.local[i], boundInternal.global[i], transf] ENDLOOP; 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; FlushBindingTable [bindingTable]; <> FOR sub: NAT IN [0 .. cellData.size) DO subTransf: Transf ~ ComposedTransf [transf, cellData.instances[sub], state]; channelPeek: WireSet ~ CheckCoreCell [self: cellData.instances[sub].type, actual: propagatedActuals[sub].global, transf: propagatedActuals[sub].transf, state: state]; <> IF (channelPeek # NIL) THEN BEGIN FOR i: NAT IN [0 .. cellData.instances[sub].type.public.size) DO <> channelPeek[i].transf _ subTransf ENDLOOP; channelPeekList _ CONS [channelPeek, channelPeekList] END; IF state.abort^ THEN {GracefulAbort [state.abort^]; RETURN}; ENDLOOP; <> IF debugBinding THEN BEGIN DrcDebug.dLog.PutF1 ["Verifying: %g\nbound internal:\n", IO.rope [ownName]]; DrcDebug.PrintWire [boundInternal.global] END; IF DrcDebug.debug THEN BEGIN FOR elle: WireSetList _ channelPeekList, elle.rest WHILE elle # NIL DO DrcDebug.dLog.PutRope ["channelPeekList.*.elt[1]: \n"]; DrcDebug.GeometryInWire [elle.first.elt[1].local, elle.first.elt[1].transf, state.attributes] ENDLOOP; END; <> FOR i: NAT IN [0 .. cellData.internal.size) DO <> <> w1: WireInstance ~ [boundInternal.local[i], boundInternal.global[i], transf]; state.tech.verifyWire [self, w1.local, state]; IF DrcDebug.debug THEN BEGIN DrcDebug.dLog.PutF ["In cell %g:\n", IO.rope [ownName]]; DrcDebug.GeometryInWire [w1.local, w1.transf, state.attributes] END; FOR j: NAT IN [i .. cellData.internal.size) DO <> <> w2: WireInstance ~ [boundInternal.local[j], boundInternal.global[j], transf]; state.tech.verifyWirePair [[self, transf], w1, w2, channelPeekList, bb, state]; IF state.abort^ THEN {GracefulAbort [state.abort^]; RETURN}; ENDLOOP ENDLOOP; <> subBB _ NEW [BoundingBoxRec[cellData.size]]; IF DrcDebug.debug THEN DrcDebug.dLog.PutF1 ["Verifying the separation between the internal of %g and its subcells.\n", IO.rope [ownName]]; FOR sub: NAT IN [0 .. cellData.size) DO subBB[sub] _ CellHull [cellData.instances[sub].type, propagatedActuals[sub].transf, state] ENDLOOP; <> FOR i: NAT IN [0 .. cellData.internal.size) DO IF NOT state.attributes.HasGeometry [boundInternal.local[i]] THEN LOOP; FOR sub: NAT IN [0 .. cellData.size) DO IF DrcDebug.debug THEN DrcDebug.dLog.PutF ["Subcell %g: %g with wire %g: local %g, global %g.\n", IO.int [sub], IO.rope [CoreOps.GetCellTypeName [cellData.instances[sub].type]], IO.int [i], IO.card [LOOPHOLE [boundInternal.local[i]]], IO.card [LOOPHOLE [boundInternal.global[i]]]]; MaterialToCellSeparation [cell: cellData.instances[sub].type, where: [self, transf], -- for error marking cellWire: propagatedActuals[sub], materialWire: [boundInternal.local[i], boundInternal.global[i], transf], window: subBB[sub], patches: channelPeekList, state: state]; IF state.abort^ THEN {GracefulAbort [state.abort^]; RETURN}; ENDLOOP ENDLOOP; <> mLog.Put1 [IO.char [' ]]; IF useTNT THEN {SweepTNT [state.nt]; SweepTNT [state.ttNt]; SweepTNT [state.ctNt]}; FOR sub1: NAT IN [0 .. cellData.size) DO maxSep1, maxSep2: CD.Number; nt: TNT; obj1: CdObj ~ CoreGeometry.GetObject [state.attributes, cellData.instances[sub1].type]; bloated1: Rect _ CDBasics.Extend [subBB[sub1], state.tech.maxSeparation]; -- quick FOR sub2: NAT IN (sub1 .. cellData.size) DO obj2: CdObj ~ CoreGeometry.GetObject [state.attributes, cellData.instances[sub2].type]; areaOfInterest: Rect; IF NOT CDBasics.Intersect [bloated1, subBB[sub2]] THEN LOOP; -- quick [maxSep1, maxSep2, nt] _ SepAndNT [cellData.instances[sub1].type, cellData.instances[sub2].type, state]; areaOfInterest _ BloatedIntersection [subBB[sub1], subBB[sub2], maxSep1, maxSep2]; IF NOT CDBasics.NonEmpty [areaOfInterest] THEN LOOP; IF useTNT AND (nt.UpdateTNT [obj1, obj2, propagatedActuals[sub1].transf, propagatedActuals[sub2].transf, propagatedActuals[sub1].global, propagatedActuals[sub2].global].wasThere) THEN LOOP; IF DrcDebug.debug THEN BEGIN 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 [subBB[sub1].x1/state.tech.lambda], IO.int [subBB[sub1].y1/state.tech.lambda], IO.int [subBB[sub1].x2/state.tech.lambda], IO.int [subBB[sub1].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 [subBB[sub2].x1/state.tech.lambda], IO.int [subBB[sub2].y1/state.tech.lambda], IO.int [subBB[sub2].x2/state.tech.lambda], IO.int [subBB[sub2].y2/state.tech.lambda]] END; CellToCellSeparation [state: state, where: [self, transf], window: areaOfInterest, cell1: cellData.instances[sub1].type, cell2: cellData.instances[sub2].type, wire1: propagatedActuals[sub1], wire2: propagatedActuals[sub2], patches: channelPeekList]; IF state.abort^ THEN {GracefulAbort [state.abort^]; RETURN} ENDLOOP ENDLOOP END; -- CheckRecord CheckTransistor: CheckCell ~ BEGIN <<[self: CoreCell, state: State, actual: Wire, transf: Transf] RETURNS [peek: WireSet _ NIL]>> <> <> boundInternal: WireInstance; boundInternal _ [self.public, BindTransistor [self.public, actual, state], transf]; peek _ NEW [WireSetRec[self.public.size]]; FOR i: NAT IN [0 .. self.public.size) DO peek[i] _ [boundInternal.local[i], boundInternal.global[i], transf] ENDLOOP; <> peek[0].gateHint _ peek[1].gateHint _ peek[2].gateHint _ NEW [WireInstance _ peek[0]] END; -- CheckTransistor DoNotCheck: CheckCell ~ BEGIN <<[self: CoreCell, state: State, actual: Wire, transf: Transf] RETURNS [peek: WireSet _ NIL]>> <<(self.class = CoreClasses.unspecifiedCellClass) OR (CoreProperties.GetProp [self.properties, doNotAnalyse]#NIL);>> self.properties _ CoreProperties.PutProp [self.properties, state.tech.checkedBy, $DrcWasHere] END; -- DoNotCheck <> noHull: Rect ~ [CD.Number.FIRST, CD.Number.FIRST, CD.Number.FIRST, CD.Number.FIRST]; <> AtomicWireHull: PUBLIC PROC [w: WireInstance, state: State] RETURNS [h: Rect] ~ BEGIN <> EachRect: CoreGeometry.EachInstanceProc ~ BEGIN <> r: Rect ~ CoreGeometry.InlineBBox [instance]; h.x1 _ MIN [h.x1, r.x1]; h.y1 _ MIN [h.y1, r.y1]; h.x2 _ MAX [h.x2, r.x2]; h.y2 _ MAX [h.y2, r.y2] END; -- EachRect IF w.local.size > 0 THEN DrcDebug.break; -- you may proceede <> IF state.attributes.HasGeometry [w.local] THEN BEGIN stored: REF Rect _ NARROW [CoreProperties.GetProp [w.local.properties, bbKey]]; IF (stored = NIL) THEN BEGIN h _ [CD.Number.LAST, CD.Number.LAST, CD.Number.FIRST, CD.Number.FIRST]; [] _ state.attributes.EnumerateGeometry [w.local, EachRect]; stored _ NEW [Rect _ h]; w.local.properties _ CoreProperties.PutProp [w.local.properties, bbKey, stored] END ELSE h _ stored^; h _ CDBasicsInline.MapRect [h, w.transf] END ELSE h _ noHull END; -- AtomicWireHull CellHull: PROC [self: CoreCell, transf: Transf, state: State] RETURNS [Rect] ~ BEGIN <> RETURN [CDBasicsInline.MapRect [state.attributes.GetObject[self].bbox, transf]] END; -- CellHull SepAndNT: PROC [cell1, cell2: CoreCell, state: State] RETURNS [maxSep1, maxSep2: CD.Number, nt: TNT] ~ BEGIN <> SELECT cell1.class FROM CoreClasses.recordCellClass => BEGIN maxSep1 _ state.tech.maxSeparation; SELECT cell2.class FROM CoreClasses.recordCellClass => {maxSep2 _ state.tech.maxSeparation; nt _ state.nt}; CoreClasses.transistorCellClass => {maxSep2 _ state.tech.ctMaxSep; nt _ state.ctNt}; ENDCASE => {maxSep2 _ state.tech.maxSeparation; nt _ state.nt} END; CoreClasses.transistorCellClass => BEGIN maxSep1 _ state.tech.ctMaxSep; SELECT cell2.class FROM CoreClasses.recordCellClass => {maxSep2 _ state.tech.ctMaxSep; nt _ state.ctNt}; CoreClasses.transistorCellClass => {maxSep1 _ maxSep2 _ state.tech.ttMaxSep; nt _ state.ttNt}; ENDCASE => {maxSep2 _ state.tech.ctMaxSep; nt _ state.ctNt} END; ENDCASE => {maxSep1 _ maxSep2 _ state.tech.maxSeparation; nt _ state.nt}; END; -- SepAndNT <> CreateBindingTable: PROC [actual, public: Wire] RETURNS [bindingTable: RefTab.Ref] ~ BEGIN tableSize: NAT _ public.size; IF actual.size # public.size THEN BEGIN IF DrcDebug.debug THEN BEGIN DrcDebug.dLog.Put1 [IO.rope ["actual.size # public.size. Actual wire:\n"]]; DrcDebug.PrintWire [actual]; DrcDebug.dLog.Put1 [IO.rope ["Public wire:\n"]]; DrcDebug.PrintWire [public]; ERROR END ELSE coreMess ["actual.size # public.size (5)", actual] END; IF (tableSize MOD 2) = 0 THEN tableSize _ tableSize.SUCC; bindingTable _ RefTab.Create [tableSize]; FOR i: NAT IN [0 .. public.size) DO [] _ RefTab.Insert [x: bindingTable, key: public[i], val: actual[i]] ENDLOOP END; -- CreateBindingTable FlushBindingTable: PROC [bindingTable: RefTab.Ref] ~ INLINE BEGIN bindingTable _ NIL END; -- FlushBindingTable PropagateBinding: PROC [state: State, bindingTable: RefTab.Ref, actual: Wire] RETURNS [boundActual: Wire] ~ BEGIN <> PropagateAtomic: PROC [state: State, bindingTable: RefTab.Ref, actual: Wire] RETURNS [boundActual: Wire] ~ INLINE BEGIN <> boundActual _ NARROW [bindingTable.Fetch [actual].val]; IF boundActual = NIL THEN BEGIN name: ROPE ~ IF DrcDebug.debug THEN IO.PutFR1 ["NewSignal-%g", IO.card [state.wireCreationCount]] ELSE CoreOps.GetShortWireName[actual].Concat[" (NewSignal)"]; boundActual _ CoreOps.CreateWires [size: 0, name: name]; state.wireCreationCount _ state.wireCreationCount.SUCC; [] _ bindingTable.Insert [key: actual, val: boundActual] END ELSE boundActual _ CoreOps.SetShortWireName [boundActual, CoreOps.GetShortWireName[actual]] END; -- PropagateAtomic boundActual _ CoreOps.CreateWires [actual.size]; FOR i: NAT IN [0 .. actual.size) DO boundActual[i] _ PropagateAtomic [state, bindingTable, actual[i]] ENDLOOP END; -- PropagateBinding BindInternal: PROC [bindingTable: RefTab.Ref, internal: Wire, state: State] RETURNS [boundInternal: Wire] ~ BEGIN <> boundInternal _ CoreOps.CopyWire [internal]; FOR i: NAT IN [0 .. internal.size) DO b: Wire ~ NARROW [bindingTable.Fetch [internal[i]].val]; <> IF (b # NIL) THEN boundInternal[i] _ b ENDLOOP END; -- BindInternal BindTransistor: PROC [public, actual: Wire, state: State] RETURNS [tw: Wire] ~ BEGIN tw _ CoreOps.CopyWire [public]; FOR i: NAT IN [0 .. public.size) DO tw[i] _ actual[i] ENDLOOP END; -- BindTransistor <> MaterialToCellProc: TYPE ~ PROC [cell: CoreCell, where: Context, cellWire, materialWire: WireInstance, window: Rect, patches: WireSetList _ NIL, state: State]; <> CellToCellProc: TYPE ~ PROC [cell1, cell2: CoreCell, where: Context, wire1, wire2: WireInstance, window: Rect, patches: WireSetList _ NIL, state: State]; <> MaterialToCellSeparation: MaterialToCellProc ~ BEGIN <> SELECT cell.class FROM CoreClasses.recordCellClass => MaterialToRecordCellSeparation [cell, where, cellWire, materialWire, window, patches, state]; CoreClasses.transistorCellClass => MaterialToTransistorSeparation [cell, where, cellWire, materialWire, window, patches, state]; CoreClasses.unspecifiedCellClass => MaterialToUnspecifiedSeparation [cell, where, cellWire, materialWire, window, patches, state]; ENDCASE => BEGIN WHILE (cell.class # CoreClasses.recordCellClass) DO cell _ cell.class.recast [cell] ENDLOOP; MaterialToRecordCellSeparation [cell, where, cellWire, materialWire, window, patches, state] END END; -- MaterialToCellSeparation MaterialToTransistorSeparation: MaterialToCellProc ~ BEGIN <<[cell: CoreCell, where: Context, cellWire, materialWire: WireInstance, window: Rect, patches: WireSetList _ NIL, state: State]>> wbb, tbb, int: Rect; -- bounding boxes boundInternal: WireInstance; atomicBoundInternal: WireSet; Intersect: PROC RETURNS [BOOL] ~ INLINE BEGIN RETURN [CDBasics.Intersect [CDBasics.Extend [tbb, state.tech.ctMaxSep], wbb]] END; -- Intersect IF state.abort^ THEN RETURN; IF (CDProperties.GetObjectProp [CoreGeometry.GetObject [state.attributes, cell], doNotAnalyse] # NIL) THEN RETURN; <> wbb _ AtomicWireHull [materialWire, state]; tbb _ CellHull [cell, cellWire.transf, state]; IF (wbb = noHull) OR (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; <> atomicBoundInternal[0].gateHint _ atomicBoundInternal[1].gateHint _ atomicBoundInternal[2].gateHint _ NEW [WireInstance _ atomicBoundInternal[0]]; IF (materialWire.global = boundInternal.global[1]) THEN materialWire.gateHint _ atomicBoundInternal[1].gateHint; IF (materialWire.global = boundInternal.global[2]) THEN materialWire.gateHint _ atomicBoundInternal[2].gateHint; <> int _ BloatedIntersection [wbb, tbb, state.tech.maxSeparation, state.tech.ctMaxSep]; FOR i: NAT IN [0 .. cell.public.size) DO IF state.abort^ THEN RETURN; state.tech.verifyWirePair [state: state, where: where, w1: atomicBoundInternal[i], w2: materialWire, relatedWires: patches, window: int] ENDLOOP END; -- MaterialToTransistorSeparation MaterialToUnspecifiedSeparation: MaterialToCellProc ~ BEGIN <<[cell: CoreCell, where: Context, cellWire, materialWire: WireInstance, window: Rect, patches: WireSetList _ NIL, state: State]>> ERROR END; -- MaterialToUnspecifiedSeparation MaterialToRecordCellSeparation: MaterialToCellProc ~ BEGIN <<[cell: CoreCell, where: Context, cellWire, materialWire: WireInstance, window: Rect, patches: WireSetList _ NIL, state: State]>> wbb, cbb, int: 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 (CDProperties.GetObjectProp [CoreGeometry.GetObject [state.attributes, cell], doNotAnalyse] # NIL) OR (cellData.internal.size = 0) THEN RETURN; <> wbb _ AtomicWireHull [materialWire, state]; cbb _ CellHull [cell, cellWire.transf, state]; IF (wbb = noHull) OR (NOT Intersect[]) THEN RETURN; <> 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; int _ BloatedIntersection [wbb, cbb, state.tech.maxSeparation, state.tech.maxSeparation]; FOR i: NAT IN [0 .. cellData.internal.size) DO state.tech.verifyWirePair [state: state, where: where, w1: atomicBoundInternal[i], w2: materialWire, relatedWires: patches, window: int] ENDLOOP; <> IF state.abort^ THEN RETURN; 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]; <> FOR sub: NAT IN [0 .. cellData.size) DO <> w: Rect ~ BloatedIntersection [CellHull [cellData.instances[sub].type, propagatedActuals[sub].transf, state], wbb, state.tech.maxSeparation, state.tech.maxSeparation]; IF NOT CDBasics.NonEmpty [w] THEN LOOP; FOR i: NAT IN [0 .. boundInternal.local.size) DO IF state.abort^ THEN RETURN; MaterialToCellSeparation [cell: cellData.instances[sub].type, where: where, -- for error marking cellWire: propagatedActuals[sub], materialWire: [boundInternal.local[i], boundInternal.global[i], cellWire.transf], window: w, patches: patches, state: state] ENDLOOP ENDLOOP END; -- MaterialToRecordCellSeparation CellToCellSeparation: CellToCellProc ~ BEGIN <<[cell1, cell2: CoreCell, where: Context, wire1, wire2: WireInstance, window: Rect, patches: WireSetList _ NIL, state: State]>> <> 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, where, wire1, wire2, window, patches, state]; RETURN END ELSE BEGIN -- swap cell1Z: CoreCell ~ cell1; wire1Z: WireInstance ~ wire1; cell1 _ cell2; cell2 _ cell1Z; wire1 _ wire2; wire2 _ wire1Z END; ENDCASE => WHILE (cell2.class # CoreClasses.recordCellClass) DO cell2 _ cell2.class.recast [cell2] ENDLOOP; SELECT cell1.class FROM CoreClasses.recordCellClass => RecordCellToRecordCellSeparation [cell1, cell2, where, wire1, wire2, window, patches, state]; CoreClasses.transistorCellClass => TransistorToRecordCellSeparation [cell1, cell2, where, wire1, wire2, window, patches, state]; CoreClasses.unspecifiedCellClass => UnspecifiedToAnyClassSeparation [cell1, cell2, where, wire1, wire2, window, patches, state]; ENDCASE => BEGIN WHILE (cell1.class # CoreClasses.recordCellClass) DO cell1 _ cell1.class.recast [cell1] ENDLOOP; RecordCellToRecordCellSeparation [cell1, cell2, where, wire1, wire2, window, patches, state] END END; -- CellToCellSeparation TransistorToTransistorSeparation: CellToCellProc ~ BEGIN <<[cell1, cell2: CoreCell, where: Context, wire1, wire2: WireInstance, window: Rect, patches: WireSetList _ NIL, state: State]>> cbb1, cbb2, w: Rect; -- bounding boxes & window boundInternal1, boundInternal2: WireInstance; atomicBoundInternal1, atomicBoundInternal2: WireSet; <> IF state.abort^ THEN RETURN; IF (CDProperties.GetObjectProp [CoreGeometry.GetObject [state.attributes, cell1], doNotAnalyse] # NIL) OR (CDProperties.GetObjectProp [CoreGeometry.GetObject [state.attributes, cell2], doNotAnalyse] # NIL) THEN RETURN; cbb1 _ CellHull [cell1, wire1.transf, state]; cbb2 _ CellHull [cell2, wire2.transf, state]; IF (NOT CDBasics.Intersect [CDBasics.Extend[cbb1,state.tech.ttMaxSep], cbb2]) THEN RETURN; <> 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; <> atomicBoundInternal1[0].gateHint _ atomicBoundInternal1[1].gateHint _ atomicBoundInternal1[2].gateHint _ NEW [WireInstance _ atomicBoundInternal1[0]]; FOR i: NAT IN [0 .. boundInternal2.local.size) DO atomicBoundInternal2[i] _ [boundInternal2.local[i], boundInternal2.global[i], wire2.transf] ENDLOOP; <> atomicBoundInternal2[0].gateHint _ atomicBoundInternal2[1].gateHint _ atomicBoundInternal2[2].gateHint _ NEW [WireInstance _ atomicBoundInternal2[0]]; w _ BloatedIntersection [cbb1, cbb2, state.tech.ctMaxSep, state.tech.ctMaxSep]; 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, where: where, w1: atomicBoundInternal1[i], w2: atomicBoundInternal2[j], relatedWires: patches, window: w] ENDLOOP ENDLOOP END; -- TransistorToTransistorSeparation TransistorToRecordCellSeparation: CellToCellProc ~ BEGIN <<[cell1, cell2: CoreCell, where: Context, wire1, wire2: WireInstance, window: Rect, patches: WireSetList _ NIL, state: State]>> cbb1, cbb2, bloated1, int: Rect; -- bounding boxes cellData2: CoreClasses.RecordCellType _ NARROW [cell2.data]; bindingTable2: RefTab.Ref; boundInternal1, boundInternal2: WireInstance; atomicBoundInternal1, atomicBoundInternal2, propagatedActuals2: WireSet; <> IF state.abort^ THEN RETURN; IF (CDProperties.GetObjectProp [CoreGeometry.GetObject [state.attributes, cell1], doNotAnalyse] # NIL) OR (CDProperties.GetObjectProp [CoreGeometry.GetObject [state.attributes, cell2], 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]; bloated1 _ CDBasics.Extend [cbb1, state.tech.ctMaxSep]; IF (NOT CDBasics.Intersect [bloated1, cbb2]) THEN RETURN; <> IF state.abort^ THEN RETURN; 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; <> atomicBoundInternal1[0].gateHint _ atomicBoundInternal1[1].gateHint _ atomicBoundInternal1[2].gateHint _ NEW [WireInstance _ atomicBoundInternal1[0]]; 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.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 [bindingTable2]; IF state.abort^ THEN RETURN; int _ BloatedIntersection [cbb1, cbb2, state.tech.ctMaxSep, state.tech.maxSeparation]; FOR i: NAT IN [0 .. wire1.global.size) DO FOR j: NAT IN [0 .. wire2.global.size) DO state.tech.verifyWirePair [state: state, where: where, w1: atomicBoundInternal1[i], w2: atomicBoundInternal2[j], relatedWires: patches, window: int] ENDLOOP ENDLOOP; <> IF state.abort^ THEN RETURN; FOR i: NAT IN [0 .. wire1.global.size) DO FOR sub: NAT IN [0 .. cellData2.size) DO subTransf: Transf ~ ComposedTransf [wire2.transf, cellData2.instances[sub], state]; bb: Rect ~ CellHull [cellData2.instances[sub].type, subTransf, state]; IF NOT CDBasics.Intersect [bloated1, bb] THEN LOOP; MaterialToCellSeparation [cell: cellData2.instances[sub].type, where: where, -- for error marking cellWire: propagatedActuals2[sub], materialWire: atomicBoundInternal1[i], window: BloatedIntersection [cbb1, bb, state.tech.ctMaxSep, state.tech.maxSeparation], patches: NIL, state: state] ENDLOOP ENDLOOP END; -- TransistorToRecordCellSeparation UnspecifiedToAnyClassSeparation: CellToCellProc ~ BEGIN <<[cell1, cell2: CoreCell, where: Context, wire1, wire2: WireInstance, window: Rect, patches: WireSetList _ NIL, state: State]>> ERROR END; -- UnspecifiedToAnyClassSeparation RecordCellToRecordCellSeparation: CellToCellProc ~ BEGIN <<[cell1, cell2: CoreCell, where: Context, wire1, wire2: WireInstance, window: Rect, patches: WireSetList _ NIL, state: State]>> cbb1, cbb2, bloated1, int: Rect; -- bounding boxes subBB1, subBB2: BoundingBox; cellData1: CoreClasses.RecordCellType _ NARROW [cell1.data]; cellData2: CoreClasses.RecordCellType _ NARROW [cell2.data]; bindingTable1, bindingTable2: RefTab.Ref; boundInternal1, boundInternal2: WireInstance; atomicBoundInternal1, atomicBoundInternal2, propagatedActuals1, propagatedActuals2: WireSet; <> IF state.abort^ THEN RETURN; IF (CDProperties.GetObjectProp [CoreGeometry.GetObject [state.attributes, cell1], doNotAnalyse] # NIL) OR (CDProperties.GetObjectProp [CoreGeometry.GetObject [state.attributes, cell2], 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]; bloated1 _ CDBasics.Extend [cbb1, state.tech.maxSeparation]; IF (NOT CDBasics.Intersect [bloated1, cbb2]) THEN RETURN; <> 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.size]]; FOR sub: NAT IN [0 .. cellData1.size) DO propagatedActuals1[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.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]; int _ BloatedIntersection [cbb1, cbb2, state.tech.maxSeparation, state.tech.maxSeparation]; FOR i: NAT IN [0 .. cellData1.internal.size) DO FOR j: NAT IN [0 .. cellData2.internal.size) DO state.tech.verifyWirePair [state: state, where: where, w1: atomicBoundInternal1[i], w2: atomicBoundInternal2[j], relatedWires: patches, window: int] ENDLOOP ENDLOOP; subBB2 _ NEW [BoundingBoxRec[cellData2.size]]; FOR sub: NAT IN [0 .. cellData2.size) DO subBB2[sub] _ CellHull [cellData2.instances[sub].type, propagatedActuals2[sub].transf, state]; int _ BloatedIntersection [cbb1, subBB2[sub], state.tech.maxSeparation, state.tech.maxSeparation]; IF NOT CDBasics.NonEmpty [int] THEN LOOP; FOR i: NAT IN [0 .. cellData1.internal.size) DO MaterialToCellSeparation [cell: cellData2.instances[sub].type, where: where, -- for error marking cellWire: propagatedActuals2[sub], materialWire: atomicBoundInternal1[i], window: int, patches: patches, state: state] ENDLOOP ENDLOOP; subBB1 _ NEW [BoundingBoxRec[cellData1.size]]; FOR sub: NAT IN [0 .. cellData1.size) DO subBB1[sub] _ CellHull [cellData1.instances[sub].type, propagatedActuals1[sub].transf, state]; int _ BloatedIntersection [subBB1[sub], cbb2, state.tech.maxSeparation, state.tech.maxSeparation]; IF NOT CDBasics.NonEmpty [int] THEN LOOP; FOR i: NAT IN [0 .. cellData2.internal.size) DO MaterialToCellSeparation [cell: cellData1.instances[sub].type, where: where, -- for error marking cellWire: propagatedActuals1[sub], materialWire: atomicBoundInternal2[i], window: int, patches: patches, state: state] ENDLOOP ENDLOOP; FOR sub1: NAT IN [0 .. cellData1.size) DO obj1: CdObj ~ CoreGeometry.GetObject [state.attributes, cellData1.instances[sub1].type]; maxSep1, maxSep2: CD.Number; nt: TNT; FOR sub2: NAT IN (sub1 .. cellData2.size) DO obj2: CdObj ~ CoreGeometry.GetObject [state.attributes, cellData2.instances[sub2].type]; areaOfInterest: Rect; IF NOT CDBasics.Intersect [bloated1, CDBasicsInline.MapRect [obj2.bbox, propagatedActuals2[sub2].transf]] THEN LOOP; -- quick [maxSep1, maxSep2, nt] _ SepAndNT [cellData1.instances[sub1].type, cellData2.instances[sub2].type, state]; areaOfInterest _ BloatedIntersection [subBB1[sub1], subBB2[sub2], maxSep1, maxSep2]; IF NOT CDBasics.NonEmpty [areaOfInterest] THEN LOOP; 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, where: where, window: areaOfInterest, cell1: cellData1.instances[sub1].type, cell2: cellData2.instances[sub2].type, wire1: propagatedActuals1[sub1], wire2: propagatedActuals2[sub2], patches: patches] ENDLOOP ENDLOOP END; -- RecordCellToRecordCellSeparation <> ClearErrors: PROC [obj: CoreCell, state: State] ~ BEGIN <> obj.properties _ CoreProperties.PutProp [obj.properties, DRVkey, NIL] END; -- ClearErrors MarkError: PUBLIC PROC [obj: CoreCell, state: State, e: ErrorRect] ~ BEGIN <> objName: ROPE = CoreOps.GetCellTypeName [obj]; violations: DRV _ NARROW [CoreProperties.GetProp [obj.properties, DRVkey]]; longMsg: ROPE _ IO.PutFR ["%g: %g", IF objName=NIL THEN IO.refAny [obj] ELSE IO.rope [objName], IO.rope[e.msg]]; done: BOOL _ FALSE; -- initialization of done important eLog.PutF1 ["%g\n", IO.rope [longMsg]]; -- eLog.Flush; state.globalErrorCount^ _ state.globalErrorCount^.SUCC; IF state.globalErrorCount^ < errorFeedbackCutOff THEN mLog.Put1 [IO.char ['|]]; IF (violations = NIL) THEN BEGIN violations _ NEW [DesignRuleViolation]; violations.count _ 1; violations.places _ LIST [e] END ELSE BEGIN violations.count _ violations.count.SUCC; violations.places _ CONS [e, violations.places] END; obj.properties _ CoreProperties.PutProp [on: obj.properties, prop: DRVkey, value: violations]; IF DrcDebug.debug THEN DrcDebug.dLog.PutF ["%g at [%g, %g, %g, %g]\n", IO.rope [longMsg], IO.int [e.r.x1], IO.int [e.r.y1], IO.int [e.r.x2], IO.int [e.r.y2]] END; -- MarkError <> PrintError: CoreProperties.PropPrintProc ~ BEGIN to.PutF1 [format: "Design rule violations: %g. ", value: IO.int [NARROW[val,DRV].count]] END; -- PrintError RegisterProperties: PROC ~ BEGIN <> <> IF (NOT CDProperties.RegisterProperty [DRVkey, $gbb]) OR (NOT CDProperties.RegisterProperty [bbKey, $gbb]) THEN IF NOT DrcDebug.debug THEN mLog.Put1 [IO.rope["Drc probably is being reexecuted.\n"]]; <> <> CoreProperties.StoreProperties [prop: DRVkey, properties: CoreProperties.Props [[CoreProperties.propPrint, NEW [CoreProperties.PropPrintProc _ PrintError]]]] END; -- RegisterProperties <> StartLog: PROC ~ BEGIN <> viewer: ViewerTools.Viewer; name: ROPE; viewer _ ViewerTools.FindExistingViewer ["Terminal Viewer"]; name _ IF (viewer # NIL) THEN "Terminal Viewer" ELSE "Genista (DRC)"; mLog _ ViewerIO.CreateViewerStreams [name, viewer].out END; -- StartLog PrintEntryShort: RefTab.EachPairAction ~ BEGIN <<[key: Key, val: Val] RETURNS [quit: BOOLEAN]>> DrcDebug.dLog.PutF ["public: %g\t actual: %g\n", IO.card [LOOPHOLE[key]], IO.card [LOOPHOLE[val]]]; RETURN [FALSE] END; -- PrintEntryShort PrintEntryLong: RefTab.EachPairAction ~ BEGIN <<[key: Key, val: Val] RETURNS [quit: BOOLEAN]>> DrcDebug.PrintWire [NARROW [key, Wire]]; DrcDebug.PrintWire [NARROW [val, Wire]]; DrcDebug.dLog.Put1 [IO.char['\n]]; RETURN [FALSE] END; -- PrintEntryLong PrintBinding: PROC [bindingTable: RefTab.Ref] ~ BEGIN <> [] _ RefTab.Pairs [bindingTable, PrintEntryShort] END; -- PrintBinding <> StartLog []; -- Should be first, so problems can be communicated RegisterProperties [] -- CD & Core END. <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<>>