<> <> <> <> <> <> DIRECTORY Atom USING [GetPName], BasicTime USING [Now], CD USING [combined, Design, FetchObjectClass, Instance, InstanceList, Layer, LayerKey, LayerTechnology, Number, Object, Orientation, original, Position, Rect, Technology], CDBasics USING [AddPoints, empty, Extend, Intersect, Intersection, SizeOfRect], CDDirectory USING [Fetch], CDErrors USING [IncludeMessage, RemoveMessages], CDOrient USING [ComposeOrient, DecomposeOrient, MapRect, original], CDProperties USING [GetProp, PutProp, PutPropOnObject, RegisterProperty], CDSimpleRules USING [MinDist, MinWidth, NotKnown], Core USING [CellType, Properties, Wire], CoreClasses USING [recordCellClass, RecordCellType, transistorCellClass, unspecifiedCellClass], CoreOps USING [CreateWires, CopyWire, GetCellTypeName, GetShortWireName, SetShortWireName], CoreProperties USING [CopyProps, GetProp, propCompare, propCopy, PropDoCopy, PropIntCompare, propPrint, PropPrintProc, Props, PutProp, RegisterProperty, StoreProperties], IO USING [card, char, Error, ErrorCode, int, noWhereStream, Put1, PutF, PutF1, PutFR, PutFR1, refAny, rope, STREAM, time], RefTab USING [Create, EachPairAction, Fetch, Insert, Pairs, Ref, SeqIndex], Rope USING [Cat, ROPE], SoS USING [CellHullProc, CellToCellProc, CheckCell, DRV, DesignRuleViolation, ErrorRect, FindGeometry, MaterialToCellProc, State, StateRec], SoSTNT USING [BlowTNT, InitTNT, InTNT, RememberTNT, SweepTNT, TNT], ViewerIO USING [CreateViewerStreams], ViewerTools USING [FindExistingViewer, Viewer]; SoSImpl: CEDAR PROGRAM IMPORTS Atom, BasicTime, CD, CDBasics, CDDirectory, CDErrors, CDOrient, CDProperties, CDSimpleRules, CoreClasses, CoreOps, CoreProperties, IO, RefTab, Rope, SoSTNT, ViewerIO, ViewerTools EXPORTS SoS ~ BEGIN OPEN SoSTNT; debug: BOOL _ FALSE; -- to start debugging enter: _ SoSImpl.Debug[] occDebug: BOOL = FALSE; -- for occasional debugging useTNT: BOOL = TRUE; -- for timing analysis only persist: BOOL _ TRUE; -- depends on Sinix (try hard to flag CD design) fast: BOOL = TRUE; -- if FALSE then SoS is purely "object oriented" break: SIGNAL = CODE; -- for debugging; related to property $SoSBreak coreMess: SIGNAL = CODE; -- clean up before issuing coreInconsistent coreInconsistent: PUBLIC ERROR = CODE; mLog: IO.STREAM; -- messages dLog: IO.STREAM _ IO.noWhereStream; -- debugging <> State: TYPE = SoS.State; -- REF StateRec; StateRec: TYPE = SoS.StateRec; <> DRV: TYPE = SoS.DRV; -- REF DesignRuleViolation DesignRuleViolation: TYPE = SoS.DesignRuleViolation; <> ErrorRect: TYPE = SoS.ErrorRect; <> <> checked: ATOM = CoreProperties.RegisterProperty [$SoSWasHere]; <> DRVkey: PUBLIC ATOM _ CoreProperties.RegisterProperty [$SoSError]; <> bbKey: ATOM _ CoreProperties.RegisterProperty [$SoSbb]; <> trace: ATOM = CoreProperties.RegisterProperty [$SoSSeparationChecked]; <> <> analysis: ATOM = CoreProperties.RegisterProperty [$SoSAnalysis]; cellHull: ATOM = CoreProperties.RegisterProperty [$SoSHull]; matToCell: ATOM = CoreProperties.RegisterProperty [$SoSmc]; cellToCell: ATOM = CoreProperties.RegisterProperty [$SoScc]; <> rectClass: ATOM = $Rect; pinClass: ATOM = $PinOb0; <> doNotAnalyse: ATOM = $DoNotDRC; previousTechnology: CD.Technology _ NIL; previousMaxSeparation: CD.Number _ 100; specialLayers: CD.Layer = 5; -- combined, highLightShade, highLightError, pinRepresentation errorFeedbackCutOff: CARDINAL = 50; -- after this number of errors, a | is no longer displayed in the ChipNDale Terminal viewer. WireSet: TYPE = REF WireSetRec; -- the wires of a set of cells WireSetRec: TYPE = RECORD [elt: SEQUENCE size: NAT OF Core.Wire]; PropSet: TYPE = REF PropSetRec; -- the wires of a set of cells PropSetRec: TYPE = RECORD [p: SEQUENCE size: NAT OF Core.Properties]; <> CheckDesignRules: PUBLIC PROC [cell: Core.CellType, design: CD.Design _ NIL, abortFlag: REF BOOL _ NIL, verbose: BOOL _ FALSE, cdObjKey, cdInstKey, cdInstListKey: ATOM] ~ BEGIN <> ENABLE BEGIN IO.Error => IF ec = StreamClosed THEN BEGIN s: IO.STREAM; m: BOOL = (stream = mLog); IF m THEN StartLog [] ELSE Debug []; s _ IF m THEN mLog ELSE dLog; CONTINUE END END; state: State _ NEW [StateRec]; messy: BOOL _ FALSE; fakeActual: Core.Wire; cellName: Rope.ROPE = CoreOps.GetCellTypeName [cell]; IO.PutF [stream: mLog, format: "\nChecking wire geometry in cell %l%g%l of design %g\n", v1: IO.rope ["b"], v2: IO.rope [cellName], v3: IO.rope ["B"], v4: IO.rope [design.name]]; IF debug THEN IO.PutF [stream: dLog, format: "\n%g. design: %g, cell: %g\n", v1: IO.time [], v2: IO.rope [design.name], v3: IF cellName = NIL THEN IO.refAny [cell] ELSE IO.rope [cellName]]; state.design _ design; state.abort _ IF abortFlag # NIL THEN abortFlag ELSE NEW [BOOL _ FALSE]; IF useTNT THEN state.nt _ InitTNT []; IF design.technology # previousTechnology THEN BEGIN previousMaxSeparation _ ComputeMaxSeparation [design.technology]; previousTechnology _ design.technology END; state.maxSeparation _ previousMaxSeparation; state.globalErrorCount _ 0; state.verbose _ verbose; state.cdObjKey _ cdObjKey; state.cdInstKey _ cdInstKey; state.cdInstListKey _ cdInstListKey; <> fakeActual _ CoreOps.CopyWire [cell.public]; CheckCoreCell [self: cell, state: state, actual: fakeActual, loc: [0, 0], orient: CDOrient.original ! coreMess => {messy _ TRUE; CONTINUE}]; IF useTNT THEN BlowTNT [state.nt]; IF messy THEN BEGIN <> IF debug THEN break; cell.properties _ CoreProperties.PutProp [cell.properties, checked, NIL]; coreInconsistent END; IO.PutF [stream: mLog, format: "\nNumber of design violations found: %l%g%l\n", v1: IO.rope ["b"], v2: IO.card [state.globalErrorCount], v3: IO.rope ["B"]] END; -- CheckDesignRules <> <> FindGeometry: TYPE = SoS.FindGeometry; <> FindCDRect: FindGeometry ~ BEGIN <> Send: PROC ~ INLINE BEGIN getRect: REF FindGeometry _ NARROW [CDProperties.GetProp [from: self.ob, prop: analysis]]; IF getRect = NIL THEN getRect _ NARROW [CDProperties.GetProp [self.ob.class, analysis]]; IF getRect = NIL THEN BEGIN mLog.Put1 [IO.rope ["\nUnexpected object class. You may proceed, but should get your stuff updated.\n"]]; SIGNAL break; getRect _ NEW [FindGeometry _ FindNoGeom] END; [r, l] _ getRect [self] END; -- Send IF fast THEN SELECT self.ob.class.objectType FROM rectClass => [r, l] _ FindRectGeom [self]; pinClass => [r, l] _ FindNoGeom [self]; ENDCASE => Send [] ELSE Send [] END; -- FindCDRect FindRectGeom: FindGeometry ~ BEGIN <> <> IF debug THEN CDProperties.PutPropOnObject [self.ob, trace, trace]; r _ CDOrient.MapRect [itemInCell: [0, 0, self.ob.size.x, self.ob.size.y], cellSize: self.ob.size, cellInstOrient: self.orientation, cellInstPos: self.location]; l _ self.ob.layer END; -- FindRectGeom FindNoGeom: FindGeometry ~ BEGIN <> IF debug THEN CDProperties.PutPropOnObject [self.ob, trace, trace] END; -- FindNoGeom RegisterGeomProcs: PROC ~ BEGIN <> [] _ CDProperties.PutProp [ onto: CD.FetchObjectClass [rectClass], prop: analysis, val: NEW [FindGeometry _ FindRectGeom]]; [] _ CDProperties.PutProp [ onto: CD.FetchObjectClass [pinClass], prop: analysis, val: NEW [FindGeometry _ FindNoGeom]] END; -- RegisterGeomProcs GetObject: PROC [cell: Core.CellType, state: State] RETURNS [obj: CD.Object] ~ INLINE BEGIN obj _ NARROW [CoreProperties.GetProp [cell.properties, state.cdObjKey], CD.Object]; IF persist AND (obj=NIL) THEN obj _ CDDirectory.Fetch [state.design, CoreOps.GetCellTypeName[cell]].object; RETURN [obj]; END; -- GetObject <> CheckCell: TYPE = SoS.CheckCell; <> CheckCoreCell: CheckCell ~ BEGIN Send: PROC ~ INLINE BEGIN check: REF CheckCell _ NARROW [CoreProperties.GetProp [self.properties, analysis]]; IF check = NIL THEN check _ NARROW [CoreProperties.GetProp [self.class.properties, analysis]]; IF check = NIL THEN BEGIN obj: CD.Object = GetObject [self, state]; IF obj = NIL THEN RETURN; -- Cell contains no rectangles check _ NEW [CheckCell _ DoNotCheck]; MarkError [self, state, [obj.class.interestRect[obj], "Cell has no provisions to be checked"]] END; check^ [self, state, actual, loc, orient] END; -- Send IF fast THEN SELECT self.class FROM CoreClasses.recordCellClass => CheckRecord [self, state, actual, loc, orient]; CoreClasses.transistorCellClass => CheckTransistor [self, state, actual, loc, orient]; CoreClasses.unspecifiedCellClass => NULL; ENDCASE => Send [] ELSE Send [] END; -- CheckCoreCell CheckRecord: CheckCell ~ BEGIN <<[self: Core.CellType, state: State, actual: Core.Wire, loc: CD.Position, orient: CD.Orientation]>> origin: CD.Position = [0, 0]; cellData: CoreClasses.RecordCellType; bindingTable: RefTab.Ref; boundInternal: Core.Wire; propagatedActuals: WireSet; -- one wire per subcell savedProps: PropSet; -- holds properties during recursion ownName: Rope.ROPE = CoreOps.GetCellTypeName [self]; IF (CoreProperties.GetProp [self.properties, doNotAnalyse]#NIL) OR (CoreProperties.GetProp[self.properties, checked]#NIL) THEN RETURN; IO.Put1 [mLog, IO.char ['.]]; IF debug THEN IO.PutF [stream: dLog, format: "\nChecking cell %l%g%l .\n", v1: IO.rope ["e"], v2: IF ownName = NIL THEN IO.refAny [self] ELSE IO.rope [ownName], v3: IO.rope ["E"]]; IF state.abort^ THEN ERROR ABORTED; ClearErrors [self, state]; cellData _ NARROW [self.data, CoreClasses.RecordCellType]; <> savedProps _ NEW [PropSetRec[actual.size]]; FOR p: NAT IN [0 .. actual.size) DO savedProps[p] _ CoreProperties.CopyProps [actual[p].properties]; ENDLOOP; bindingTable _ CreateBindingTable [actual: actual, public: self.public]; boundInternal _ BindInternal [bindingTable, cellData.internal, state]; IF occDebug THEN BEGIN dLog.PutF1 ["Binding and propagating: %g. Binding table:\n", IO.rope [ownName]]; PrintBinding [bindingTable]; dLog.PutF1 ["Bound internal of %g:\n", IO.rope [ownName]]; PrintWire [boundInternal] END; <> propagatedActuals _ NEW [WireSetRec[cellData.size]]; FOR sub: NAT IN [0 .. cellData.size) DO propagatedActuals[sub] _ PropagateBinding [state, bindingTable, cellData.instances[sub].actual] ENDLOOP; FlushBindingTable [bindingTable]; <> FOR sub: NAT IN [0 .. cellData.size) DO cdInst: CD.Instance = NARROW [CoreProperties.GetProp [cellData.instances[sub].properties, state.cdInstKey]]; IF (cdInst = NIL) THEN coreMess; CheckCoreCell [self: cellData.instances[sub].type, state: state, actual: propagatedActuals[sub], loc: CDBasics.AddPoints [loc, cdInst.location], orient: CDOrient.ComposeOrient [orient, cdInst.orientation]] ENDLOOP; <> IF occDebug THEN BEGIN dLog.PutF1 ["Verifying: %g\nbound internal:\n", IO.rope [ownName]]; PrintWire [boundInternal] END; <> FOR i: NAT IN [0 .. cellData.internal.size) DO FOR j: NAT IN (i .. cellData.internal.size) DO MaterialSeparation [state: state, cell: self, w1: boundInternal[i], w2: boundInternal[j], loc1: origin, loc2: origin, orient1: CD.original, orient2: CD.original] ENDLOOP; WidthCheck [self, state, boundInternal[i]] ENDLOOP; <> FOR sub: NAT IN [0 .. cellData.size) DO cdInst: CD.Instance = NARROW [CoreProperties.GetProp [cellData.instances[sub].properties, state.cdInstKey]]; IF (cdInst = NIL) THEN coreMess; FOR i: NAT IN [0 .. cellData.internal.size) DO MaterialToCellSeparation [state: state, self: cellData.instances[sub].type, actual: propagatedActuals[sub], wire: cellData.internal[i], father: self, -- for error marking materialLoc: loc, cellLoc: cdInst.location, materialOrient: orient, cellOrient: cdInst.orientation] ENDLOOP ENDLOOP; <> IF useTNT THEN SweepTNT [state.nt]; FOR sub1: NAT IN [0 .. cellData.size) DO cdInst1: CD.Instance = NARROW [CoreProperties.GetProp [cellData.instances[sub1].properties, state.cdInstKey]]; IF (cdInst1 = NIL) THEN coreMess; FOR sub2: NAT IN (sub1 .. cellData.size) DO cdInst2: CD.Instance = NARROW [CoreProperties.GetProp [cellData.instances[sub2].properties, state.cdInstKey]]; IF (cdInst2 = NIL) THEN coreMess; IF useTNT AND (InTNT [state.nt, cdInst1, cdInst2, propagatedActuals[sub1], propagatedActuals[sub2]]) THEN LOOP; CellToCellSeparation [state: state, self: cellData.instances[sub1].type, otherCell: cellData.instances[sub2].type, selfActual: propagatedActuals[sub1], otherActual: propagatedActuals[sub2], father: self, -- for error marking selfLoc: CDBasics.AddPoints [loc, cdInst1.location], otherLoc: CDBasics.AddPoints [loc, cdInst2.location], selfOrient: CDOrient.ComposeOrient [orient, cdInst1.orientation], otherOrient: CDOrient.ComposeOrient [orient, cdInst2.orientation]]; IF useTNT THEN RememberTNT [state.nt, cdInst1, cdInst2, propagatedActuals[sub1], propagatedActuals[sub2]] ENDLOOP ENDLOOP; <> FOR p: NAT IN [0 .. self.public.size) DO actual[p].properties _ CoreProperties.CopyProps [savedProps[p]]; ENDLOOP; self.properties _ CoreProperties.PutProp [self.properties, checked, checked] END; -- CheckRecord CheckTransistor: CheckCell ~ BEGIN <<[self: Core.CellType, state: State, actual: Core.Wire, loc: CD.Position, orient: CD.Orientation]>> <> DoNotCheck [self, state, actual, loc, orient] END; -- CheckTransistor DoNotCheck: CheckCell ~ BEGIN <<[self: Core.CellType, state: State, actual: Core.Wire, loc: CD.Position, orient: CD.Orientation]>> <<(self.class = CoreClasses.unspecifiedCellClass) OR (CoreProperties.GetProp [self.properties, doNotAnalyse]#NIL);>> self.properties _ CoreProperties.PutProp [self.properties, checked, checked] END; -- DoNotCheck RegisterAnalysisProcs: PROC ~ BEGIN <> CoreClasses.recordCellClass.properties _ CoreProperties.PutProp [ on: CoreClasses.recordCellClass.properties, prop: analysis, value: NEW [CheckCell _ CheckRecord]]; CoreClasses.transistorCellClass.properties _ CoreProperties.PutProp [CoreClasses.transistorCellClass.properties, analysis, NEW [CheckCell _ CheckTransistor]]; CoreClasses.unspecifiedCellClass.properties _ CoreProperties.PutProp [CoreClasses.unspecifiedCellClass.properties, analysis, NEW [CheckCell _ DoNotCheck]]; END; -- RegisterAnalysisProcs <> CellHullProc: TYPE = SoS.CellHullProc; <> AtomicWireHull: PROC [w: Core.Wire, state: State] RETURNS [h: CD.Rect _ CDBasics.empty] ~ BEGIN <> stored: REF CD.Rect _ NARROW [CoreProperties.GetProp [w.properties, bbKey]]; geom: CD.InstanceList; IF w.size > 0 THEN break; -- wire is not atomic IF (stored # NIL) THEN RETURN [stored^]; geom _ NARROW [CoreProperties.GetProp [w.properties, state.cdInstListKey]]; FOR g: CD.InstanceList _ geom, g.rest WHILE g # NIL DO r: CD.Rect = FindCDRect [g.first].r; 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] ENDLOOP; stored _ NEW [CD.Rect _ h]; w.properties _ CoreProperties.PutProp [w.properties, bbKey, stored] END; -- AtomicWireHull CellHull: CellHullProc ~ BEGIN <> <> hull: REF CellHullProc _ NEW [CellHullProc]; SELECT self.class FROM CoreClasses.recordCellClass => hull^ _ RecordCellHull; CoreClasses.transistorCellClass => hull^ _ TransistorHull; CoreClasses.unspecifiedCellClass => hull^ _ UnspecifiedHull; ENDCASE => BEGIN hull _ NARROW [CoreProperties.GetProp [self.properties, cellHull]]; IF hull = NIL THEN hull _ NARROW [CoreProperties.GetProp [self.class.properties, cellHull]]; IF hull = NIL THEN hull^ _ UnspecifiedHull; END; RETURN [hull^ [self, state]] END; -- CellHull; RecordCellHull: CellHullProc ~ BEGIN <<[self: Core.CellType, state: State] RETURNS [h: CD.Rect _ CDBasics.empty]>> stored: REF CD.Rect _ NARROW [CoreProperties.GetProp [self.properties, bbKey]]; IF (stored = NIL) THEN BEGIN cellData: CoreClasses.RecordCellType = NARROW [self.data, CoreClasses.RecordCellType]; IF cellData.internal.size = 0 THEN break; -- atomic wire not expected here FOR i: NAT IN [0 .. cellData.internal.size) DO a: CD.Rect = AtomicWireHull [cellData.internal[i], state]; h.x1 _ MIN [h.x1, a.x1]; h.y1 _ MIN [h.y1, a.y1]; h.x2 _ MAX [h.x2, a.x2]; h.y2 _ MAX [h.y2, a.y2] ENDLOOP; FOR sub: NAT IN [0 .. cellData.size) DO <> r: CD.Rect = CellHull [cellData.instances[sub].type, state]; 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] ENDLOOP; stored _ NEW [CD.Rect _ h]; self.properties _ CoreProperties.PutProp [self.properties, bbKey, stored] END END; -- RecordCellHull TransistorHull: CellHullProc ~ BEGIN <<[self: Core.CellType, state: State] RETURNS [h: CD.Rect _ CDBasics.empty]>> stored: REF CD.Rect _ NARROW [CoreProperties.GetProp [self.properties, bbKey]]; IF (stored = NIL) THEN BEGIN wire: Core.Wire = self.public; IF wire.size = 0 THEN break; -- atomic wire not expected here FOR i: NAT IN [0 .. wire.size) DO a: CD.Rect = AtomicWireHull [wire[i], state]; h.x1 _ MIN [h.x1, a.x1]; h.y1 _ MIN [h.y1, a.y1]; h.x2 _ MAX [h.x2, a.x2]; h.y2 _ MAX [h.y2, a.y2] ENDLOOP; stored _ NEW [CD.Rect _ h]; self.properties _ CoreProperties.PutProp [self.properties, bbKey, stored] END END; -- TransistorHull UnspecifiedHull: CellHullProc ~ BEGIN <<[self: Core.CellType, state: State] RETURNS [h: CD.Rect _ CDBasics.empty]>> stored: REF CD.Rect _ NARROW [CoreProperties.GetProp [self.properties, bbKey]]; IF (stored = NIL) THEN BEGIN stored _ NEW [CD.Rect _ h]; self.properties _ CoreProperties.PutProp [self.properties, bbKey, stored] END END; -- UnspecifiedHull RegisterPruningProcs: PROC ~ BEGIN <> CoreClasses.recordCellClass.properties _ CoreProperties.PutProp [ on: CoreClasses.recordCellClass.properties, prop: cellHull, value: NEW [CellHullProc _ RecordCellHull]]; CoreClasses.transistorCellClass.properties _ CoreProperties.PutProp [CoreClasses.transistorCellClass.properties, cellHull, NEW [CellHullProc _ TransistorHull]]; CoreClasses.unspecifiedCellClass.properties _ CoreProperties.PutProp [CoreClasses.unspecifiedCellClass.properties, cellHull, NEW [CellHullProc _ UnspecifiedHull]] END; -- RegisterPruningProcs <> CreateBindingTable: PROC [actual, public: Core.Wire] RETURNS [bindingTable: RefTab.Ref] ~ BEGIN tableSize: RefTab.SeqIndex _ public.size; IF actual.size # public.size THEN BEGIN IF debug THEN BEGIN dLog.Put1 [IO.rope ["actual.size # public.size. Actual wire:\n"]]; PrintWire [actual]; dLog.Put1 [IO.rope ["Public wire:\n"]]; PrintWire [public]; ERROR END ELSE coreMess 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: Core.Wire] RETURNS [boundActual: Core.Wire] ~ BEGIN <> PropagateAtomic: PROC [state: State, bindingTable: RefTab.Ref, actual: Core.Wire] RETURNS [boundActual: Core.Wire] ~ INLINE BEGIN <> boundActual _ NARROW [RefTab.Fetch [bindingTable, actual].val]; <> IF boundActual = NIL THEN BEGIN name: Rope.ROPE = IF debug THEN IO.PutFR1 ["New signal # %g", IO.card [state.wireCreationCount]] ELSE "New signal by SoS"; boundActual _ CoreOps.CreateWires [size: 0, name: name]; state.wireCreationCount _ state.wireCreationCount.SUCC; [] _ RefTab.Insert [x: bindingTable, 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: Core.Wire, state: State] RETURNS [boundInternal: Core.Wire] ~ BEGIN <> boundInternal _ CoreOps.CopyWire [internal]; FOR i: NAT IN [0 .. internal.size) DO b: Core.Wire = NARROW [RefTab.Fetch [bindingTable, internal[i]].val]; <> IF b # NIL THEN BEGIN <> boundInternal[i] _ b; <> <> <> boundInternal[i].properties _ CoreProperties.CopyProps [internal[i].properties] END ENDLOOP END; -- BindInternal BindTransistor: PROC [public, actual: Core.Wire, state: State] RETURNS [tw: Core.Wire] ~ BEGIN <> tw _ CoreOps.CopyWire [public]; FOR i: NAT IN [0 .. public.size) DO tw[i] _ actual[i]; <> <> tw[i].properties _ CoreProperties.CopyProps [public[i].properties] ENDLOOP END; -- BindTransistor <> <> <> <> <> <> <> <> MaterialToCellProc: TYPE = SoS.MaterialToCellProc; <> CellToCellProc: TYPE = SoS.CellToCellProc; <> WidthCheck: PROC [c: Core.CellType, s: State, w: Core.Wire] ~ BEGIN <> <> min: CD.Number; r: CD.Rect; l: CD.Layer; key: ATOM; il: CD.InstanceList = NARROW [CoreProperties.GetProp [w.properties, s.cdInstListKey]]; FOR i: CD.InstanceList _ il, i.rest WHILE i # NIL DO [r, l] _ FindCDRect [i.first]; key _ CD.LayerKey [l]; IF (l < specialLayers) OR (key = NIL) THEN LOOP; min _ CDSimpleRules.MinWidth [l]; IF ((r.x2 - r.x1) < min) OR ((r.y2 - r.y1) < min) THEN MarkError [c, s, [r, Rope.Cat ["Width violation on layer ", Atom.GetPName [CD.LayerKey [l]], " (wire ", CoreOps.GetShortWireName[w], ")"]]] ENDLOOP END; -- WidthCheck MaterialSeparation: PROC [cell: Core.CellType, state: State, w1, w2: Core.Wire, loc1, loc2: CD.Position, orient1, orient2: CD.Orientation] ~ BEGIN <> <> cd1, cd2: CD.InstanceList; obj1, obj2: CD.Object; r1, r2, r, s: CD.Rect; l1, l2: CD.Layer; key1, key2: ATOM; sep: CD.Number; Intersect: PROC RETURNS [BOOL] ~ INLINE BEGIN RETURN [CDBasics.Intersect [CDBasics.Extend[AtomicWireHull[w1,state],state.maxSeparation], AtomicWireHull[w2,state]]] END; -- Intersect IF state.abort^ THEN ERROR ABORTED; IF (w1 = w2) THEN RETURN; -- aequipotential material cd1 _ NARROW [CoreProperties.GetProp [w1.properties, state.cdInstListKey]]; cd2 _ NARROW [CoreProperties.GetProp [w2.properties, state.cdInstListKey]]; IF (cd1 = NIL) OR (cd2 = NIL) THEN RETURN; -- Skip wires without geometry IF (NOT Intersect[]) THEN RETURN; -- or whose geometry is too far apart. FOR outer: CD.InstanceList _ cd1, outer.rest WHILE outer # NIL DO obj1 _ outer.first.ob; [r1, l1] _ FindCDRect [outer.first]; key1 _ CD.LayerKey [l1]; <> IF (l1 < specialLayers) OR (key1 = NIL) THEN LOOP; r1 _ CDOrient.MapRect [itemInCell: r1, cellSize: outer.first.ob.size, cellInstOrient: orient1, cellInstPos: loc1]; FOR inner: CD.InstanceList _ cd2, inner.rest WHILE inner # NIL DO IF state.abort^ THEN ERROR ABORTED; obj2 _ inner.first.ob; <> IF debug AND (obj1#NIL) AND (obj2#NIL) AND (CDProperties.GetProp[obj1,$SoSBreak]#NIL) AND (CDProperties.GetProp[obj1,$SoSBreak]#NIL) THEN SIGNAL break; [r2, l2] _ FindCDRect [inner.first]; key2 _ CD.LayerKey [l2]; IF (l2 < specialLayers) OR (key2 = NIL) THEN LOOP; sep _ CDSimpleRules.MinDist [l1, l2 ! CDSimpleRules.NotKnown => sep _ 0]; IF sep = 0 THEN LOOP; r2 _ CDOrient.MapRect [r2, inner.first.ob.size, orient2, loc2]; r _ CDBasics.Extend [r1, sep / 2]; s _ CDBasics.Extend [r2, sep / 2]; IF ((r.x1> MarkError [cell, state, [CDBasics.Intersection[r,s], Rope.Cat["Separation violation between ", rect1, " and ", rect2]]]; END ENDLOOP -- inner ENDLOOP -- outer END; -- MaterialSeparation MaterialToCellSeparation: MaterialToCellProc ~ BEGIN <<[self: Core.CellType, state: State, actual, wire: Core.Wire, father: Core.CellType, materialLoc, cellLoc: CD.Position, materialOrient, cellOrient: CD.Orientation]>> <> Send: PROC ~ INLINE BEGIN check: REF MaterialToCellProc _ NARROW [CoreProperties.GetProp [self.properties, matToCell]]; IF check = NIL THEN check _ NARROW [CoreProperties.GetProp [self.class.properties, matToCell]]; IF check = NIL THEN BEGIN obj: CD.Object = GetObject [self, state]; IF obj = NIL THEN RETURN; -- Cell contains no rectangles check _ NEW [MaterialToCellProc _ MaterialToUnspecifiedSeparation]; MarkError [self, state, [obj.class.interestRect[obj], "Cell has no provisions to be checked"]] END; check^ [self, state, actual, wire, father, materialLoc, cellLoc, materialOrient, cellOrient] END; -- Send IF fast THEN SELECT self.class FROM CoreClasses.recordCellClass => MaterialToRecordCellSeparation [self, state, actual, wire, father, materialLoc, cellLoc, materialOrient, cellOrient]; CoreClasses.transistorCellClass => MaterialToTransistorSeparation [self, state, actual, wire, father, materialLoc, cellLoc, materialOrient, cellOrient]; CoreClasses.unspecifiedCellClass => MaterialToUnspecifiedSeparation [self, state, actual, wire, father, materialLoc, cellLoc, materialOrient, cellOrient]; ENDCASE => Send [] ELSE Send [] END; -- MaterialToCellSeparation MaterialToTransistorSeparation: MaterialToCellProc ~ BEGIN <<[self: Core.CellType, state: State, actual, wire: Core.Wire, father: Core.CellType, materialLoc, cellLoc: CD.Position, materialOrient, cellOrient: CD.Orientation]>> wbb, tbb: CD.Rect; -- bounding boxes tw: Core.Wire; Intersect: PROC RETURNS [BOOL] ~ INLINE BEGIN RETURN [CDBasics.Intersect [CDBasics.Extend[tbb,state.maxSeparation], wbb]] END; -- Intersect IF state.abort^ THEN ERROR ABORTED; IF (CoreProperties.GetProp [self.properties, doNotAnalyse] # NIL) THEN RETURN; <> wbb _ AtomicWireHull [wire, state]; wbb _ CDOrient.MapRect [itemInCell: wbb, cellSize: CDBasics.SizeOfRect [wbb], cellInstOrient: materialOrient, cellInstPos: materialLoc]; tbb _ TransistorHull [self, state]; tbb _ CDOrient.MapRect [itemInCell: tbb, cellSize: CDBasics.SizeOfRect [tbb], cellInstOrient: cellOrient, cellInstPos: cellLoc]; IF (NOT Intersect[]) THEN RETURN; tw _ BindTransistor [self.public, actual, state]; <> FOR i: NAT IN [0 .. tw.size) DO MaterialSeparation [state: state, cell: father, w1: tw[i], w2: wire, loc1: cellLoc, loc2: materialLoc, orient1: cellOrient, orient2: materialOrient] ENDLOOP END; -- MaterialToTransistorSeparation MaterialToUnspecifiedSeparation: MaterialToCellProc ~ BEGIN <<[self: Core.CellType, state: State, actual, wire: Core.Wire, father: Core.CellType, materialLoc, cellLoc: CD.Position, materialOrient, cellOrient: CD.Orientation]>> NULL END; -- MaterialToUnspecifiedSeparation MaterialToRecordCellSeparation: MaterialToCellProc ~ BEGIN <<[self: Core.CellType, state: State, actual, wire: Core.Wire, father: Core.CellType, materialLoc, cellLoc: CD.Position, materialOrient, cellOrient: CD.Orientation]>> wbb, cbb: CD.Rect; -- bounding boxes boundInternal: Core.Wire; propagatedActuals: WireSet; -- one wire per subcell bindingTable: RefTab.Ref; cellData: CoreClasses.RecordCellType _ NARROW [self.data]; Intersect: PROC RETURNS [BOOL] ~ INLINE BEGIN RETURN [CDBasics.Intersect [CDBasics.Extend[cbb,state.maxSeparation], wbb]] END; -- Intersect IF state.abort^ THEN ERROR ABORTED; IF (CoreProperties.GetProp [self.properties, doNotAnalyse] # NIL) OR (cellData.internal.size = 0) THEN RETURN; <> wbb _ AtomicWireHull [wire, state]; wbb _ CDOrient.MapRect [itemInCell: wbb, cellSize: CDBasics.SizeOfRect [wbb], cellInstOrient: materialOrient, cellInstPos: materialLoc]; cbb _ RecordCellHull [self, state]; cbb _ CDOrient.MapRect [itemInCell: cbb, cellSize: CDBasics.SizeOfRect [cbb], cellInstOrient: cellOrient, cellInstPos: cellLoc]; IF (NOT Intersect[]) THEN RETURN; <> bindingTable _ CreateBindingTable [actual: actual, public: self.public]; boundInternal _ BindInternal [bindingTable, cellData.internal, state]; FOR i: NAT IN [0 .. boundInternal.size) DO MaterialSeparation [state: state, cell: father, w1: boundInternal[i], w2: wire, loc1: cellLoc, loc2: materialLoc, orient1: cellOrient, orient2: materialOrient] ENDLOOP; <> propagatedActuals _ NEW [WireSetRec[cellData.size]]; FOR sub: NAT IN [0 .. cellData.size) DO propagatedActuals[sub] _ PropagateBinding [state, bindingTable, cellData.instances[sub].actual] ENDLOOP; FlushBindingTable [bindingTable]; <> FOR sub: NAT IN [0 .. cellData.size) DO cdInst: CD.Instance = NARROW [CoreProperties.GetProp [cellData.instances[sub].properties, state.cdInstKey]]; IF (cdInst = NIL) THEN coreMess; MaterialToCellSeparation [self: cellData.instances[sub].type, state: state, actual: propagatedActuals[sub], wire: wire, father: self, materialLoc: materialLoc, cellLoc: CDBasics.AddPoints [cellLoc, cdInst.location], materialOrient: materialOrient, cellOrient: CDOrient.ComposeOrient [cellOrient, cdInst.orientation]] ENDLOOP END; -- MaterialToRecordCellSeparation CellToCellSeparation: CellToCellProc ~ BEGIN <<[self: Core.CellType, state: State, otherCell: Core.CellType, selfActual, otherActual: Core.Wire, father: Core.CellType, selfLoc, otherLoc: CD.Position, selfOrient, otherOrient: CD.Orientation]>> <> Send: PROC ~ INLINE BEGIN check: REF CellToCellProc _ NARROW [CoreProperties.GetProp [self.properties, cellToCell]]; IF check = NIL THEN check _ NARROW [CoreProperties.GetProp [self.class.properties, cellToCell]]; IF check = NIL THEN BEGIN obj: CD.Object = GetObject [self, state]; IF obj = NIL THEN RETURN; -- Cell contains no rectangles check _ NEW [CellToCellProc _ UnspecifiedToAnyClassSeparation]; MarkError [self, state, [obj.class.interestRect[obj], "Cell has no provisions to be checked"]] END; check^ [self, state, otherCell, selfActual, otherActual, father, selfLoc, otherLoc, selfOrient, otherOrient] END; -- Send SELECT otherCell.class FROM CoreClasses.unspecifiedCellClass => RETURN; CoreClasses.recordCellClass => NULL; -- default case CoreClasses.transistorCellClass => -- nasty case IF self.class = CoreClasses.transistorCellClass THEN BEGIN IF fast THEN TransistorToTransistorSeparation [self, state, otherCell, selfActual, otherActual, father, selfLoc, otherLoc, selfOrient, otherOrient] ELSE Send []; RETURN END ELSE BEGIN -- swap selfZ: Core.CellType = self; selfActualZ: Core.Wire = selfActual; selfLocZ: CD.Position = selfLoc; selfOrientZ: CD.Orientation = selfOrient; self _ otherCell; otherCell _ selfZ; selfActual _ otherActual; otherActual _ selfActualZ; selfLoc _ otherLoc; otherLoc _ selfLocZ; selfOrient _ otherOrient; otherOrient _ selfOrientZ END; ENDCASE => ERROR; IF fast THEN SELECT self.class FROM CoreClasses.recordCellClass => RecordCellToRecordCellSeparation [self, state, otherCell, selfActual, otherActual, father, selfLoc, otherLoc, selfOrient, otherOrient]; CoreClasses.transistorCellClass => TransistorToRecordCellSeparation [self, state, otherCell, selfActual, otherActual, father, selfLoc, otherLoc, selfOrient, otherOrient]; CoreClasses.unspecifiedCellClass => UnspecifiedToAnyClassSeparation [self, state, otherCell, selfActual, otherActual, father, selfLoc, otherLoc, selfOrient, otherOrient]; ENDCASE => Send [] ELSE Send [] END; -- CellToCellSeparation TransistorToRecordCellSeparation: CellToCellProc ~ BEGIN <<[self: Core.CellType, state: State, otherCell: Core.CellType, selfActual, otherActual: Core.Wire, father: Core.CellType, selfLoc, otherLoc: CD.Position, selfOrient, otherOrient: CD.Orientation]>> cbb1, cbb2: CD.Rect; -- bounding boxes othersCellData: CoreClasses.RecordCellType _ NARROW [otherCell.data]; othersBindingTable: RefTab.Ref; tw: Core.Wire; othersBoundInternal: Core.Wire; ownName: Rope.ROPE = CoreOps.GetCellTypeName [self]; otherName: Rope.ROPE = CoreOps.GetCellTypeName [otherCell]; Intersect: PROC RETURNS [BOOL] ~ INLINE BEGIN RETURN [CDBasics.Intersect [CDBasics.Extend[cbb1,state.maxSeparation], cbb2]] END; -- Intersect <> IF state.abort^ THEN ERROR ABORTED; IF (CoreProperties.GetProp [self.properties, doNotAnalyse]#NIL) OR (CoreProperties.GetProp [otherCell.properties, doNotAnalyse]#NIL) THEN RETURN; IF debug THEN BEGIN IO.PutF [stream: dLog, format: "Checking transistor %l%g%l vs. %g. ", v1: IO.rope ["e"], v2: IF ownName = NIL THEN IO.refAny [self] ELSE IO.rope [ownName], v3: IO.rope ["E"], v4: IF otherName = NIL THEN IO.refAny [otherCell] ELSE IO.rope [otherName]]; IO.PutF [stream: dLog, format: "Rel. orient: %g, dist: (%g, %g).\n", v1: IO.int [CDOrient.DecomposeOrient [otherOrient, selfOrient]], v2: IO.int [(otherLoc.x - selfLoc.x) / previousTechnology.lambda], v3: IO.int [(otherLoc.y - selfLoc.y) / previousTechnology.lambda]] END; cbb1 _ RecordCellHull [self, state]; cbb1 _ CDOrient.MapRect [itemInCell: cbb1, cellSize: CDBasics.SizeOfRect [cbb1], cellInstOrient: selfOrient, cellInstPos: selfLoc]; cbb2 _ RecordCellHull [otherCell, state]; cbb2 _ CDOrient.MapRect [itemInCell: cbb2, cellSize: CDBasics.SizeOfRect [cbb2], cellInstOrient: otherOrient, cellInstPos: otherLoc]; IF (NOT Intersect[]) THEN RETURN; <> IF state.abort^ THEN ERROR ABORTED; othersBindingTable _ CreateBindingTable [actual: otherActual, public: otherCell.public]; othersBoundInternal _ BindInternal [othersBindingTable, othersCellData.internal, state]; tw _ BindTransistor [self.public, selfActual, state]; FlushBindingTable [othersBindingTable]; FOR i: NAT IN [0 .. tw.size) DO FOR j: NAT IN [0 .. othersCellData.internal.size) DO MaterialSeparation [state: state, cell: father, -- the cell getting the error flag -- w1: tw[i], w2: othersBoundInternal[j], loc1: selfLoc, loc2: otherLoc, orient1: selfOrient, orient2: otherOrient] ENDLOOP ENDLOOP END; -- TransistorToRecordCellSeparation TransistorToTransistorSeparation: CellToCellProc ~ BEGIN <<[self: Core.CellType, state: State, otherCell: Core.CellType, selfActual, otherActual: Core.Wire, father: Core.CellType, selfLoc, otherLoc: CD.Position, selfOrient, otherOrient: CD.Orientation]>> cbb1, cbb2: CD.Rect; -- bounding boxes tw1, tw2: Core.Wire; ownName: Rope.ROPE = CoreOps.GetCellTypeName [self]; otherName: Rope.ROPE = CoreOps.GetCellTypeName [otherCell]; Intersect: PROC RETURNS [BOOL] ~ INLINE BEGIN RETURN [CDBasics.Intersect [CDBasics.Extend[cbb1,state.maxSeparation], cbb2]] END; -- Intersect <> IF state.abort^ THEN ERROR ABORTED; IF (CoreProperties.GetProp [self.properties, doNotAnalyse]#NIL) OR (CoreProperties.GetProp [otherCell.properties, doNotAnalyse]#NIL) THEN RETURN; cbb1 _ RecordCellHull [self, state]; cbb1 _ CDOrient.MapRect [itemInCell: cbb1, cellSize: CDBasics.SizeOfRect [cbb1], cellInstOrient: selfOrient, cellInstPos: selfLoc]; cbb2 _ RecordCellHull [otherCell, state]; cbb2 _ CDOrient.MapRect [itemInCell: cbb2, cellSize: CDBasics.SizeOfRect [cbb2], cellInstOrient: otherOrient, cellInstPos: otherLoc]; IF (NOT Intersect[]) THEN RETURN; <> IF state.abort^ THEN ERROR ABORTED; tw1 _ BindTransistor [self.public, selfActual, state]; tw2 _ BindTransistor [otherCell.public, otherActual, state]; FOR i: NAT IN [0 .. tw1.size) DO FOR j: NAT IN [0 .. tw2.size) DO MaterialSeparation [state: state, cell: father, -- the cell getting the error flag -- w1: tw1[i], w2: tw2[j], loc1: selfLoc, loc2: otherLoc, orient1: selfOrient, orient2: otherOrient] ENDLOOP ENDLOOP END; -- TransistorToTransistorSeparation UnspecifiedToAnyClassSeparation: CellToCellProc ~ BEGIN <<[self: Core.CellType, state: State, otherCell: Core.CellType, selfActual, otherActual: Core.Wire, father: Core.CellType, selfLoc, otherLoc: CD.Position, selfOrient, otherOrient: CD.Orientation]>> NULL END; -- UnspecifiedToAnyClassSeparation RecordCellToRecordCellSeparation: CellToCellProc ~ BEGIN <<[self: Core.CellType, state: State, otherCell: Core.CellType, selfActual, otherActual: Core.Wire, father: Core.CellType, selfLoc, otherLoc: CD.Position, selfOrient, otherOrient: CD.Orientation]>> cbb1, cbb2: CD.Rect; -- bounding boxes ownCellData: CoreClasses.RecordCellType _ NARROW [self.data]; othersCellData: CoreClasses.RecordCellType _ NARROW [otherCell.data]; ownBindingTable, othersBindingTable: RefTab.Ref; ownBoundInternal, othersBoundInternal: Core.Wire; ownName: Rope.ROPE = CoreOps.GetCellTypeName [self]; otherName: Rope.ROPE = CoreOps.GetCellTypeName [otherCell]; Intersect: PROC RETURNS [BOOL] ~ INLINE BEGIN RETURN [CDBasics.Intersect [CDBasics.Extend[cbb1,state.maxSeparation], cbb2]] END; -- Intersect <> IF state.abort^ THEN ERROR ABORTED; IF (CoreProperties.GetProp [self.properties, doNotAnalyse]#NIL) OR (CoreProperties.GetProp [otherCell.properties, doNotAnalyse]#NIL) THEN RETURN; IF debug THEN BEGIN IO.PutF [stream: dLog, format: "Checking cell %l%g%l vs. %g. ", v1: IO.rope ["e"], v2: IF ownName = NIL THEN IO.refAny [self] ELSE IO.rope [ownName], v3: IO.rope ["E"], v4: IF otherName = NIL THEN IO.refAny [otherCell] ELSE IO.rope [otherName]]; IO.PutF [stream: dLog, format: "Rel. orient: %g, dist: (%g, %g).\n", v1: IO.int [CDOrient.DecomposeOrient [otherOrient, selfOrient]], v2: IO.int [(otherLoc.x - selfLoc.x) / previousTechnology.lambda], v3: IO.int [(otherLoc.y - selfLoc.y) / previousTechnology.lambda]] END; cbb1 _ RecordCellHull [self, state]; cbb1 _ CDOrient.MapRect [itemInCell: cbb1, cellSize: CDBasics.SizeOfRect [cbb1], cellInstOrient: selfOrient, cellInstPos: selfLoc]; cbb2 _ RecordCellHull [otherCell, state]; cbb2 _ CDOrient.MapRect [itemInCell: cbb2, cellSize: CDBasics.SizeOfRect [cbb2], cellInstOrient: otherOrient, cellInstPos: otherLoc]; IF (NOT Intersect[]) THEN RETURN; <> IF state.abort^ THEN ERROR ABORTED; ownBindingTable _ CreateBindingTable [actual: selfActual, public: self.public]; othersBindingTable _ CreateBindingTable [actual: otherActual, public: otherCell.public]; ownBoundInternal _ BindInternal [ownBindingTable, ownCellData.internal, state]; othersBoundInternal _ BindInternal [othersBindingTable, othersCellData.internal, state]; FlushBindingTable [ownBindingTable]; FlushBindingTable [othersBindingTable]; FOR i: NAT IN [0 .. ownCellData.internal.size) DO FOR j: NAT IN [0 .. othersCellData.internal.size) DO MaterialSeparation [state: state, cell: father, -- the cell getting the error flag -- w1: ownBoundInternal[i], w2: othersBoundInternal[j], loc1: selfLoc, loc2: otherLoc, orient1: selfOrient, orient2: otherOrient] ENDLOOP ENDLOOP END; -- RecordCellToRecordCellSeparation ComputeMaxSeparation: PROC [technology: CD.Technology] RETURNS [maxSeparation: CD.Number] ~ BEGIN <> maxSeparation _ 0; FOR s1: CD.Layer IN CD.Layer DO IF CD.LayerTechnology[s1] = technology THEN FOR s2: CD.Layer IN CD.Layer DO IF CD.LayerTechnology[s2] = technology THEN BEGIN sep: CD.Number = CDSimpleRules.MinDist [s1, s2 ! CDSimpleRules.NotKnown => LOOP]; -- try to filter out inappropriate layers maxSeparation _ MAX [maxSeparation, sep] END ENDLOOP ENDLOOP END; -- ComputeMaxSeparation RegisterSeparationProcs: PROC ~ BEGIN <> CoreClasses.recordCellClass.properties _ CoreProperties.PutProp [ on: CoreClasses.recordCellClass.properties, prop: matToCell, value: NEW [MaterialToCellProc _ MaterialToRecordCellSeparation]]; CoreClasses.transistorCellClass.properties _ CoreProperties.PutProp [CoreClasses.transistorCellClass.properties, matToCell, NEW [MaterialToCellProc _ MaterialToTransistorSeparation]]; CoreClasses.unspecifiedCellClass.properties _ CoreProperties.PutProp [CoreClasses.unspecifiedCellClass.properties, matToCell, NEW [MaterialToCellProc _ MaterialToUnspecifiedSeparation]]; CoreClasses.recordCellClass.properties _ CoreProperties.PutProp [ on: CoreClasses.recordCellClass.properties, prop: cellToCell, value: NEW [CellToCellProc _ RecordCellToRecordCellSeparation]]; CoreClasses.transistorCellClass.properties _ CoreProperties.PutProp [CoreClasses.transistorCellClass.properties, cellToCell, NEW [CellToCellProc _ TransistorToRecordCellSeparation]]; CoreClasses.unspecifiedCellClass.properties _ CoreProperties.PutProp [CoreClasses.unspecifiedCellClass.properties, cellToCell, NEW [CellToCellProc _ UnspecifiedToAnyClassSeparation]]; END; -- RegisterSeparationProcs <> ClearErrors: PROC [obj: Core.CellType, state: State] ~ BEGIN <> CDErrors.RemoveMessages [ design: state.design, ob: NARROW [CoreProperties.GetProp [obj.properties, state.cdObjKey]], owner: DRVkey]; obj.properties _ CoreProperties.PutProp [obj.properties, DRVkey, NIL] END; -- ClearErrors MarkError: PROC [obj: Core.CellType, state: State, e: ErrorRect] ~ BEGIN <> objName: Rope.ROPE = CoreOps.GetCellTypeName [obj]; cdObj: CD.Object _ GetObject [obj, state]; violations: DRV _ NARROW [CoreProperties.GetProp [obj.properties, DRVkey]]; longMsg: Rope.ROPE _ IO.PutFR ["%g: %g", IF objName=NIL THEN IO.refAny [obj] ELSE IO.rope [objName], IO.rope[e.msg]]; done: BOOL _ FALSE; -- important 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]; state.globalErrorCount _ state.globalErrorCount.SUCC; IF state.globalErrorCount < errorFeedbackCutOff THEN IO.Put1 [mLog, IO.char ['|]]; IF (state.design # NIL) AND (cdObj # NIL) THEN done _ CDErrors.IncludeMessage [ design: state.design, ob: cdObj, rect: CDBasics.Extend [e.r, 1], message: e.msg, owner: DRVkey].done; IF state.abort^ THEN ERROR ABORTED; IF NOT done THEN longMsg _ Rope.Cat [r1: longMsg, r2: " (not flagged in the layout)"]; IF debug THEN IO.PutF1 [dLog, "%g\n", IO.rope [longMsg]]; IF state.verbose THEN IO.PutF1 [mLog, "\n%g\n", IO.rope [longMsg]] END; -- MarkError <> PrintError: CoreProperties.PropPrintProc ~ BEGIN IO.PutF1 [stream: to, format: "SoS error count = %g ", value: IO.int [NARROW[val,DRV].count]] END; -- PrintError PrintChecked: CoreProperties.PropPrintProc ~ BEGIN IO.Put1 [stream: to, value: IO.rope ["Design rules checked"]] END; -- PrintChecked RegisterProperties: PROC ~ BEGIN <> <> IF (NOT CDProperties.RegisterProperty [DRVkey, $gbb]) OR (NOT CDProperties.RegisterProperty [checked, $gbb]) OR (NOT CDProperties.RegisterProperty [bbKey, $gbb]) OR (NOT CDProperties.RegisterProperty [cellHull, $gbb]) OR (NOT CDProperties.RegisterProperty [trace, $gbb]) THEN IF NOT debug THEN ERROR; -- somebody is already using it. This check is necessary because in some future ChipNDale and Core may get the same property scope and they will then need different keys. <> CoreProperties.StoreProperties [prop: DRVkey, properties: CoreProperties.Props [[CoreProperties.propCopy, CoreProperties.PropDoCopy], [CoreProperties.propCompare, CoreProperties.PropIntCompare], [CoreProperties.propPrint, NEW [CoreProperties.PropPrintProc _ PrintError]]]]; CoreProperties.StoreProperties [prop: checked, properties: CoreProperties.Props [[CoreProperties.propCopy, CoreProperties.PropDoCopy], [CoreProperties.propPrint, NEW [CoreProperties.PropPrintProc _ PrintChecked]]]]; CoreProperties.StoreProperties [prop: bbKey, properties: CoreProperties.Props [[CoreProperties.propCopy, CoreProperties.PropDoCopy]]]; CoreProperties.StoreProperties [prop: cellHull, properties: CoreProperties.Props [[CoreProperties.propCopy, CoreProperties.PropDoCopy]]]; CoreProperties.StoreProperties [prop: trace, properties: CoreProperties.Props [[CoreProperties.propCopy, CoreProperties.PropDoCopy]]]; CoreProperties.StoreProperties [prop: analysis, properties: CoreProperties.Props [[CoreProperties.propCopy, CoreProperties.PropDoCopy]]]; CoreProperties.StoreProperties [prop: matToCell, properties: CoreProperties.Props [[CoreProperties.propCopy, CoreProperties.PropDoCopy]]]; CoreProperties.StoreProperties [prop: cellToCell, properties: CoreProperties.Props [[CoreProperties.propCopy, CoreProperties.PropDoCopy]]]; END; -- RegisterProperties <> StartLog: PROC ~ BEGIN <> viewer: ViewerTools.Viewer; dummy: IO.STREAM; name: Rope.ROPE; viewer _ ViewerTools.FindExistingViewer ["Terminal"]; name _ IF viewer # NIL THEN "Terminal" ELSE "Son of Spinifex"; [in: dummy, out: mLog] _ ViewerIO.CreateViewerStreams [name, viewer]; END; -- StartLog Debug: PROC ~ BEGIN <> viewer: ViewerTools.Viewer; dummy: IO.STREAM; debug _ TRUE; viewer _ ViewerTools.FindExistingViewer ["SoS debug"]; [in: dummy, out: dLog] _ ViewerIO.CreateViewerStreams ["SoS debug", viewer]; IF dLog = NIL THEN dLog _ mLog END; -- Debug PrintWire: PROC [w: Core.Wire] ~ BEGIN <> dLog.PutF ["%g %g %g\n", IO.rope [CoreOps.GetShortWireName[w]], IO.card [LOOPHOLE[w]], IO.refAny [w]]; FOR i: NAT IN [0 .. w.size) DO dLog.PutF ["\t(%g) %g %g %g\n", IO.card [i], IO.rope [CoreOps.GetShortWireName[w[i]]], IO.card [LOOPHOLE[w[i]]], IO.refAny [w[i]]] ENDLOOP END; -- PrintWire PrintEntryShort: RefTab.EachPairAction ~ BEGIN <<[key: Key, val: Val] RETURNS [quit: BOOLEAN]>> 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]>> PrintWire [NARROW [key, Core.Wire]]; PrintWire [NARROW [val, Core.Wire]]; 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 IF debug THEN Debug[]; RegisterProperties []; -- CD & Core RegisterGeomProcs []; -- ChipNDale RegisterPruningProcs []; RegisterAnalysisProcs []; RegisterSeparationProcs [] -- Core END.