<> <> <> <> <> <> <> <> DIRECTORY Atom USING [GetPName], BasicTime USING [Now], CD USING [backgroundLayer, commentLayer, Design, errorLayer, FetchObjectClass, Instance, InstanceList, Layer, LayerKey, LayerTechnology, Number, Object, Orientation, original, outlineLayer, Position, Rect, selectionLayer, shadeLayer, Technology, undefLayer], 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, PutObjectProp, RegisterProperty], CDSimpleRules USING [MaxWidth, MinDist, MinWidth, NotKnown], Core USING [CellType, Properties, Wire], CoreClasses USING [recordCellClass, RecordCellType, transistorCellClass, unspecifiedCellClass], CoreGeometry, CoreOps USING [CreateWires, CopyWire, GetCellTypeName, GetShortWireName, SetShortWireName], CoreProperties USING [CopyProps, GetProp, propCompare, propCopy, PropDoCopy, PropIntCompare, propPrint, PropPrintProc, Props, PutProp, RegisterProperty, StoreProperties], FinchSmarts USING [CurrentFinchState, FinchState, GetProcs, Procs, RecordReason], FS USING [StreamOpen], IO USING [card, char, Close, Error, ErrorCode, int, noWhereStream, Put1, PutF, PutF1, PutFR, PutFR1, PutRope, refAny, rope, STREAM, time], RefTab USING [Create, EachPairAction, Fetch, Insert, Pairs, Ref, SeqIndex], Rope USING [Cat, ROPE], Mayday 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]; MaydayImpl: CEDAR PROGRAM IMPORTS Atom, BasicTime, CD, CDBasics, CDDirectory, CDErrors, CDOrient, CDProperties, CDSimpleRules, CoreClasses, CoreGeometry, CoreOps, CoreProperties, FinchSmarts, FS, IO, RefTab, Rope, SoSTNT, ViewerIO, ViewerTools EXPORTS Mayday ~ BEGIN OPEN SoSTNT; debug: BOOL _ FALSE; -- to start debugging enter: _ MaydayImpl.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 Mayday is purely "object oriented" break: SIGNAL = CODE; -- for debugging; related to property $MaydayBreak panic: SIGNAL = CODE; -- cannot communicate violations coreMess: SIGNAL [reason: Rope.ROPE, torch: REF ANY] = CODE; -- clean up before issuing coreInconsistent coreInconsistent: PUBLIC ERROR [reason: Rope.ROPE, torch: REF ANY] = CODE; mLog: IO.STREAM; -- messages eLog: IO.STREAM; -- error log dLog: IO.STREAM _ IO.noWhereStream; -- debugging <> State: TYPE = Mayday.State; -- REF StateRec; StateRec: TYPE = Mayday.StateRec; DRV: TYPE = Mayday.DRV; -- REF DesignRuleViolation DesignRuleViolation: TYPE = Mayday.DesignRuleViolation; <> ErrorRect: TYPE = Mayday.ErrorRect; <> <> checked: ATOM = CoreProperties.RegisterProperty [$MaydayWasHere]; <> DRVkey: PUBLIC ATOM _ CoreProperties.RegisterProperty [$MaydayError]; <> bbKey: ATOM _ CoreProperties.RegisterProperty [$Maydaybb]; <> trace: ATOM = CoreProperties.RegisterProperty [$MaydaySeparationChecked]; <> <> analysis: ATOM = CoreProperties.RegisterProperty [$MaydayAnalysis]; cellHull: ATOM = CoreProperties.RegisterProperty [$MaydayHull]; matToCell: ATOM = CoreProperties.RegisterProperty [$Maydaymc]; cellToCell: ATOM = CoreProperties.RegisterProperty [$Maydaycc]; <> rectClass: ATOM = $Rect; pinClass: ATOM = $PinOb0; <> doNotAnalyse: ATOM = $DoNotDRC; previousTechnology: CD.Technology _ NIL; previousMaxSeparation: CD.Number _ 75 * 8; specialLayers: CD.Layer = MAX [CD.shadeLayer, CD.errorLayer, CD.backgroundLayer, CD.outlineLayer, CD.selectionLayer, CD.commentLayer] + 1; <> <> errorFeedbackCutOff: CARDINAL = 50; -- after this number of errors, a | is no longer displayed in the ChipNDale Terminal viewer (if it may be displayed at all). 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 properties of a set of cells PropSetRec: TYPE = RECORD [p: SEQUENCE size: NAT OF Core.Properties]; <> CheckDesignRules: PUBLIC PROC [cell: Core.CellType, decoration: CoreGeometry.Decoration, design: CD.Design _ NIL, abortFlag: REF BOOL _ NIL, verbose, shy, placebo: BOOL _ FALSE, cdObjKey: ATOM] RETURNS [quantity: CARDINAL _ 1] ~ 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; panic => GOTO paranoia END; state: State _ NEW [StateRec]; messy, okToType: BOOL _ FALSE; abortionCause: Rope.ROPE; debugTorch: REF ANY; shadowCell: Core.CellType; -- to be implemented fakeActual: Core.Wire; cellName: Rope.ROPE = CoreOps.GetCellTypeName [cell]; designName: Rope.ROPE = IF design#NIL THEN design.name ELSE "in the sky"; state.shy _ shy; -- must be first statement eLog _ FS.StreamOpen [fileName: "[]<>Temp>DRC>Mayday.log", accessOptions: create, keep: 5, extendFileProc: NIL, remoteCheck: FALSE, wDir: NIL]; -- keep is 5 because of incremental use eLog.PutF1 ["Error log by Mayday. Design: %g\n\n", IO.rope [designName]]; IF placebo THEN BEGIN FOR wait: NAT IN [0 .. 1984] DO IO.PutF1 [IO.noWhereStream, "Yes, you are really a very bright, smart and intelligent guy. Your Core structure is so great, it really gives me the frills. I feel so great looking at it. I'll propose you for the next Turing Award. [%g]", IO.card[wait]] ENDLOOP; <> RETURN END; [] _ Msg ["Welcome to S o S, the son of Spinifex. I will try to find all design rule violations in your design. Have a nice time."]; <> shadowCell _ CopyCell [cell]; -- to be implemented <> okToType _ IF state.shy THEN NOT (Msg [cellName]) ELSE TRUE; IF okToType THEN 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 [designName]]; IF debug THEN IO.PutF [stream: dLog, format: "\n%g. design: %g, cell: %g\n", v1: IO.time [], v2: IO.rope [designName], v3: IF cellName = NIL THEN IO.refAny [shadowCell] 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 = NIL) OR (design.technology = NIL) THEN BEGIN state.maxSeparation _ previousMaxSeparation _ 75 * 8; <> previousTechnology _ NIL END ELSE 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.decoration _ decoration; <> fakeActual _ CoreOps.CopyWire [shadowCell.public]; CheckCoreCell [self: shadowCell, state: state, actual: fakeActual, loc: [0, 0], orient: CDOrient.original ! coreMess => {messy _ TRUE; abortionCause _ reason; debugTorch _ torch; CONTINUE}]; IF useTNT THEN BlowTNT [state.nt]; IF messy THEN BEGIN <> IF debug THEN break; cell.properties _ CoreProperties.PutProp [shadowCell.properties, checked, NIL]; [] _ Msg ["Your Core data structure is busted! You lose, you lose,"]; <> eLog.PutRope ["\nDRC failed. Your Core data structure is busted! You lose, you lose."]; eLog.Close []; coreInconsistent [abortionCause, debugTorch] END; < 0 and we do not know whether what we found in it is meaningful.>> quantity _ state.globalErrorCount; <> [] _ Msg ["This is S o S speaking."]; SELECT quantity FROM 0 => [] _ Msg ["Congratulations, I could not find any new design rule violations in your design. Please check for old violations. Have a nice time."]; 1 => [] _ Msg ["Sorry, there is a new design rule violation in your design. Please fix it."]; ENDCASE => [] _ Msg [IO.PutFR1 ["You have %g new bugs in your design. You lose, you lose,", IO.card [quantity]]]; IF NOT state.shy THEN IO.PutF [stream: mLog, format: "\nNumber of new design violations found: %l%g%l\n", v1: IO.rope ["b"], v2: IO.card [state.globalErrorCount], v3: IO.rope ["B"]]; <> eLog.PutRope ["\nDRC terminated normally."]; eLog.Close []; EXITS <> paranoia => -- cannot communicate with anybody {eLog.PutRope ["\nThis is paranoia."]; eLog.Close []} END; -- CheckDesignRules <> <> FindGeometry: TYPE = Mayday.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 [] _ Msg ["Unexpected object class. You may proceed, but should get your stuff updated."]; 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.PutObjectProp [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.PutObjectProp [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) AND (state.design#NIL) THEN obj _ CDDirectory.Fetch [state.design, CoreOps.GetCellTypeName[cell]].object; RETURN [obj]; END; -- GetObject <> CopyCell: PROC [original: Core.CellType] RETURNS [copy: Core.CellType] ~ BEGIN <> copy _ original -- << Yuck. Terrible hack. >> To be implemented END; -- CopyCell CheckCell: TYPE = Mayday.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; IF state.shy THEN [] _ Msg [ownName] ELSE 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 = CoreGeometry.GetTransf[state.decoration, cellData.instances[sub]]; IF (cdInst = NIL) THEN coreMess ["Core record cell has no geometry (1)", cellData]; 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 = CoreGeometry.GetTransf[state.decoration, cellData.instances[sub]]; IF (cdInst = NIL) THEN coreMess ["Core record cell has no geometry (2)", cellData]; 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 = CoreGeometry.GetTransf[state.decoration, cellData.instances[sub1]]; IF (cdInst1 = NIL) THEN coreMess ["Core record cell has no geometry (3)", cellData]; FOR sub2: NAT IN (sub1 .. cellData.size) DO cdInst2: CD.Instance = CoreGeometry.GetTransf[state.decoration, cellData.instances[sub2]]; IF (cdInst2 = NIL) THEN coreMess ["Core record cell has no geometry (4)", cellData]; 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 = Mayday.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 BEGIN <> [] _ Msg ["Your Core data structure is busted! You do not lose yet."]; break -- you may proceede END; IF (stored # NIL) THEN RETURN [stored^]; geom _ CoreGeometry.GetGeometry[state.decoration, w]; 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; -- you may proceede <> 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; -- you may proceede <> 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 ["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: 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 Mayday"; 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 = Mayday.MaterialToCellProc; <> CellToCellProc: TYPE = Mayday.CellToCellProc; <> WidthCheck: PROC [c: Core.CellType, s: State, w: Core.Wire] ~ BEGIN <> <> min, max, a, b: CD.Number; -- a and b are such that a > b r: CD.Rect; l: CD.Layer; key: ATOM; il: CD.InstanceList = CoreGeometry.GetGeometry[s.decoration, w]; 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]; max _ CDSimpleRules.MaxWidth [l]; a _ MAX [(r.x2 - r.x1), (r.y2 - r.y1)]; b _ MIN [(r.x2 - r.x1), (r.y2 - r.y1)]; IF (a < min) OR (b < min) OR (a > max) OR (b > max) THEN BEGIN <<<< Total Hack. Yuk. >>>> <> splitA: CD.Number = 3 * min; splitB: CD.Number = min; -- yuk, spit <> IF (CD.LayerKey[l] = $cut) AND (a = splitA) AND (b = splitB) THEN NULL -- mumble ELSE MarkError [c, s, [r, Rope.Cat ["Width violation on layer ", Atom.GetPName [CD.LayerKey [l]], " (wire ", CoreOps.GetShortWireName[w], ")"]]] END ENDLOOP END; -- WidthCheck MaterialSeparation: PROC [cell: Core.CellType, state: State, w1, w2: Core.Wire, loc1, loc2: CD.Position, orient1, orient2: CD.Orientation] ~ BEGIN <> <> aequipotential: BOOL; 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 NotCuts: PROC RETURNS [BOOL] ~ INLINE BEGIN <> RETURN [NOT (((key1 = $cut) OR (key1 = $cut2)) AND ((key2 = $cut) OR (key2 = $cut2)))] END; -- NotCuts SameRect: PROC RETURNS [BOOL] ~ INLINE BEGIN RETURN [(l1 = l2) AND (r1.x1 = r2.x1) AND (r1.y1 = r2.y1) AND (r1.x2 = r2.x2) AND (r1.y2 = r2.y2)] END; -- SameRect IF state.abort^ THEN ERROR ABORTED; <> cd1 _ CoreGeometry.GetGeometry[state.decoration, w1]; cd2 _ CoreGeometry.GetGeometry[state.decoration, w2]; 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,$MaydayBreak]#NIL) AND (CDProperties.GetProp[obj1,$MaydayBreak]#NIL) THEN SIGNAL break; [r2, l2] _ FindCDRect [inner.first]; <> aequipotential _ CDBasics.Intersect [r1, r2]; key2 _ CD.LayerKey [l2]; IF aequipotential AND NotCuts[] THEN LOOP; 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]; IF aequipotential AND SameRect[] THEN LOOP; 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 = CoreGeometry.GetTransf[state.decoration, cellData.instances[sub]]; IF (cdInst = NIL) THEN coreMess ["Core record subcell has no geometry (6)", cellData]; 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 <> IF state.shy THEN RETURN; IF (state.design # NIL) THEN CDErrors.RemoveMessages [design: state.design, ob: GetObject [obj, state], 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; -- initialization of done important eLog.PutF1 ["%g\n", IO.rope [longMsg]]; 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; state.globalErrorCount _ state.globalErrorCount.SUCC; IF state.abort^ THEN ERROR ABORTED; IF state.shy AND (NOT Msg [longMsg]) THEN panic <> ELSE BEGIN IF state.globalErrorCount < errorFeedbackCutOff THEN IO.Put1 [mLog, IO.char ['|]]; obj.properties _ CoreProperties.PutProp [on: obj.properties, prop: DRVkey, value: violations]; IF (state.design # NIL) AND (cdObj # NIL) THEN done _ CDErrors.IncludeMessage [ design: state.design, ob: cdObj, rect: CDBasics.Extend [e.r, 4], message: e.msg, owner: DRVkey].done; 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]] END; IF (state.verbose) THEN IO.PutF1 [mLog, "\n%g\n", IO.rope [longMsg]] END; -- MarkError <> PrintError: CoreProperties.PropPrintProc ~ BEGIN IO.PutF1 [stream: to, format: "Mayday 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 mLog.Put1 [IO.rope["Mayday probably is being reexecuted.\n"]]; <> <> 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 Msg: PROC [msg: Rope.ROPE] RETURNS [ok: BOOL] ~ BEGIN <> sLogProcs: FinchSmarts.Procs; <> <> <<$unknown means Finch hasn't been loaded; its' procedures aren't around.>> <<$stopped means that Finch isn't connected up with the server.>> <<$running is the only state where it makes sense to get the procs and call them.>> IF (FinchSmarts.CurrentFinchState[] # running) THEN RETURN [FALSE]; sLogProcs _ FinchSmarts.GetProcs []; IF (sLogProcs = NIL) OR (NOT sLogProcs.finchIsRunning []) THEN RETURN [FALSE]; <> <> RETURN [sLogProcs.textToSpeech [msg.Cat [" "]] = ok] <> END; -- Msg Debug: PROC ~ BEGIN <> viewer: ViewerTools.Viewer; dummy: IO.STREAM; debug _ TRUE; viewer _ ViewerTools.FindExistingViewer ["Mayday debug"]; [in: dummy, out: dLog] _ ViewerIO.CreateViewerStreams ["Mayday 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. <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<>>