DIRECTORY CD USING [Design, ObPtr, ApplicationPtr, ApplicationList, Rect], CDDirectory USING [Name], CDProperties USING [GetPropFromObject, PutPropOnObject, GetProp, PutProp], CDOrient USING [MapPosition, ComposeOrient, RectAt], TerminalIO USING [WriteRope], IO USING [STREAM, ROS, RopeFromROS, PutFR, PutF, Put, int, rope], Atom USING [GetPName, PutPropOnList, GetPropFromList], Rope USING [ROPE, Cat], RefTab USING [GetSize, Pairs, EachPairAction], Process USING [Detach], BasicTime USING [GMT, Now, Period], CornerStitching USING [DumpCache], SpinifexAtoms USING [spinifex], SpinifexInvert USING [Inversion, Invert, ClientDataProc], SpinifexCircuit USING [LogicalCell, Circuit, TechHandle, TranslateGeometry, CircuitNode, AreaPerimRec, NodeLinkage, QuadTree, SpinifexLayerIndex, Rectangle, AreaSplit, AttachedNode, MergeRecList, MergeRec], SpinifexOutput USING [PrintCircuit], SpinifexLayers USING [AnalyzeGeometry], SpinifexCellPredicates USING [IsLogicalCell, CanDisplayErrors], SpinifexAccess ; SpinifexAccessImpl: CEDAR MONITOR IMPORTS CDDirectory, CDProperties, CDOrient, TerminalIO, IO, Atom, Rope, RefTab, Process, BasicTime, SpinifexAtoms, SpinifexInvert, SpinifexLayers, SpinifexCircuit, SpinifexOutput, SpinifexCellPredicates, CornerStitching EXPORTS SpinifexAccess ~ BEGIN saveSpinifex: BOOLEAN _ TRUE; -- Use the interpreter to set this to TRUE. LogicalCell: TYPE ~ SpinifexCircuit.LogicalCell; Inversion: TYPE ~ SpinifexInvert.Inversion; FetchInvocationKey: ENTRY PROCEDURE [design: CD.Design] RETURNS [INT] ~ { ENABLE UNWIND => NULL; key: REF INT ~ NARROW[CDProperties.GetProp[from~ design, prop~ SpinifexAtoms.spinifex]]; IF key = NIL THEN { CDProperties.PutProp[onto~ design, prop~ SpinifexAtoms.spinifex, val~ NEW[INT _ 0]]; RETURN [0] } ELSE RETURN [(key^ _ key^.SUCC)] }; AnalyzeCell: PUBLIC PROCEDURE [design: CD.Design, hierarchyRoots: LIST OF CD.ApplicationPtr, formatKey: REF ANY] RETURNS [BOOLEAN] ~ { ready: LIST OF REF Inversion; done: LIST OF REF LogicalCell; techProp: REF ANY; technologyHandle: REF SpinifexCircuit.TechHandle; startTime: BasicTime.GMT _ BasicTime.Now[]; IF design.technology = NIL THEN { TerminalIO.WriteRope["Design does not specify a technology\n"]; ERROR ABORTED } ELSE IF (techProp _ CDProperties.GetProp[from~ design.technology, prop~ SpinifexAtoms.spinifex]) = NIL THEN { TerminalIO.WriteRope[ Rope.Cat[ "\"", design.technology.name, "\" technology lacks analysis capability\n"]]; ERROR ABORTED } ELSE WITH techProp SELECT FROM tpOK: REF SpinifexCircuit.TechHandle => technologyHandle _ tpOK; ENDCASE => { TerminalIO.WriteRope[ Rope.Cat[ "\"", design.technology.name, "\" technology capability is invalid\n"]]; ERROR ABORTED }; FOR hrl: LIST OF CD.ApplicationPtr _ hierarchyRoots, hrl.rest WHILE hrl # NIL DO IF ~SpinifexCellPredicates.CanDisplayErrors[hrl.first.ob] THEN { TerminalIO.WriteRope[ Rope.Cat[ "\"", CDDirectory.Name[hrl.first.ob], "\" Is not valid as root object for analysis, reason: error rectangles cannot be attached to objects of type $", Atom.GetPName[hrl.first.ob.p.objectType], "\n"]]; ERROR ABORTED }; ENDLOOP; ready _ SpinifexInvert.Invert[design, hierarchyRoots, NewLogicalCell]; done _ NIL; TerminalIO.WriteRope["Hierarchy processing order determined\n"]; { jobQ: LIST OF REF Inversion _ ready; sync: REF SyncRec _ NEW[SyncRec]; doneTail: LIST OF REF LogicalCell; done _ CONS[NIL,NIL]; doneTail _ done; sync.totals _ NEW[TotRec]; -- Development statistics. sync.key _ FetchInvocationKey[design]; WHILE jobQ # NIL DO cell: REF LogicalCell ~ NARROW[jobQ.first.data]; refSpex: REF ANY ~ CDProperties.GetProp[ from~cell.cellObj, prop~SpinifexAtoms.spinifex]; WITH refSpex SELECT FROM cir: REF SpinifexCircuit.Circuit => { cell.circuit _ cir; DoCell[cell, sync, jobQ, FALSE]; }; ENDCASE => IF refSpex # NIL THEN ERROR ELSE { cell.circuit _ NEW [SpinifexCircuit.Circuit]; cell.circuit.technologyHandle _ technologyHandle; Start[sync]; TRUSTED { Process.Detach[FORK DoCell[cell, sync, jobQ, TRUE]] } }; doneTail.rest _ CONS[ NARROW[jobQ.first.data], NIL]; doneTail _ doneTail.rest; jobQ _ Next[jobQ, sync]; ENDLOOP; TotalStorageUsage[sync.totals]; -- Development statistics. done _ done.rest }; CornerStitching.DumpCache[]; TerminalIO.WriteRope[ IO.PutFR["Elapsed time = %gs\n", IO.int[ BasicTime.Period[ from~ startTime, to~ BasicTime.Now[]]] ]]; IF formatKey # NIL THEN { SpinifexOutput.PrintCircuit[done, formatKey]; TerminalIO.WriteRope[ IO.PutFR["Elapsed time = %gs\n", IO.int[ BasicTime.Period[ from~ startTime, to~ BasicTime.Now[]]] ]] }; RETURN [TRUE] }; AnalyzeArea: PUBLIC PROCEDURE [design: CD.Design, Region: CD.Rect] RETURNS [BOOLEAN] ~ { TerminalIO.WriteRope[ "\"AnalyzeArea\" NOT YET IMPLEMENTED\n"]; RETURN [TRUE] }; NewLogicalCell: SpinifexInvert.ClientDataProc -- [design: CD.Design, appl: CD.ApplicationPtr, pos: CD.DesignPosition, orient: CD.Orientation, parent: REF Inversion] RETURNS [data: REF ANY _ NIL] -- ~ { cell: REF LogicalCell ~ NEW[LogicalCell _ [cellObj~ appl.ob, design~ design]]; IF ~SpinifexCellPredicates.CanDisplayErrors[appl.ob] THEN { parentCell: REF LogicalCell ~ NARROW[parent.data]; cell.errorContext _ IF parentCell.errorContext = NIL THEN parentCell.cellObj ELSE parentCell.errorContext; cell.relativePos _ CDOrient.MapPosition[CDOrient.RectAt[ pos~ pos, size~ appl.ob.size, orient~ orient], parentCell.cellObj.size, parentCell.relativeOrient, parentCell.relativePos]; cell.relativeOrient _ CDOrient.ComposeOrient[ orient, parentCell.relativeOrient]; }; data _ cell }; ErrorCountAtom: ATOM ~ $SpinifexDRCCount; DoCell: PROCEDURE [cell: REF LogicalCell, sync: REF SyncRec, readyQ: LIST OF REF Inversion, changed: BOOLEAN] ~ { ENABLE ABORTED => { KillParent: ENTRY PROCEDURE ~ { ENABLE UNWIND => NULL; sync.abortParent _ TRUE; BROADCAST sync.QChange; }; KillParent[]; REJECT }; cir: REF SpinifexCircuit.Circuit ~ cell.circuit; statusReport: IO.STREAM ~ IO.ROS[]; IF changed THEN { TerminalIO.WriteRope[ Rope.Cat[ "Analyzing: \"", CDDirectory.Name[cell.cellObj], "\" "]]; SpinifexCircuit.TranslateGeometry[cell]; TerminalIO.WriteRope[ ". "]; SpinifexLayers.AnalyzeGeometry[cell]; IF cell.circuit.technologyHandle.CellPostProcess # NIL THEN cell.circuit.technologyHandle.CellPostProcess[cell]; CDProperties.PutPropOnObject[onto~cell.cellObj, prop~SpinifexAtoms.spinifex, val~cir]; statusReport.PutF["Finished: \"%g\" %g/%g devices ", IO.rope[CDDirectory.Name[cell.cellObj]], IO.int[cir.linkageCount.inSelf+cir.linkageCount.inChildren], IO.int[cir.linkageCount.inSelf]]; IF cell.errorCount # 0 THEN { cell.circuit.properties _ cell.circuit.properties.PutPropOnList[ ErrorCountAtom, NEW[ INT _ cell.errorCount]]; statusReport.PutF["\007 %g Design Rule Error%g%g ", IO.int[cell.errorCount], IO.rope[ IF cell.errorCount > 1 THEN "s" ELSE ""], IO.rope[ IF cell.errorContext # NIL THEN Rope.Cat[" displayed in cell \"", CDDirectory.Name[cell.errorContext], "\""] ELSE ""] ]; } } ELSE { errorCount: REF INT ~ NARROW[cell.circuit.properties.GetPropFromList[ ErrorCountAtom]]; statusReport.PutF["Skipped: \"%g\", already analyzed; %g/%g devices ", IO.rope[CDDirectory.Name[cell.cellObj]], IO.int[cir.linkageCount.inSelf+cir.linkageCount.inChildren], IO.int[cir.linkageCount.inSelf]]; IF errorCount # NIL THEN statusReport.PutF["\007 %g Design Rule Error%g previously ", IO.int[errorCount^], IO.rope[ IF errorCount^ > 1 THEN "s" ELSE ""] ]; }; ReportStorageUsage[statusReport, NARROW[CDProperties.GetProp[ from~cell.cellObj, prop~SpinifexAtoms.spinifex]], sync.totals]; -- Development statistics. statusReport.Put[ IO.rope[ "\n"]]; TerminalIO.WriteRope[ statusReport.RopeFromROS]; Finished[sync, readyQ, changed]; cir.invocationKey _ sync.key; }; SyncRec: TYPE ~ RECORD [ QChange: CONDITION, jobCount: INT _ 0, JobLim: INT _ 1, totals: REF TotRec _ NIL, key: INT, abortParent: BOOLEAN _ FALSE ]; Start: ENTRY PROCEDURE [sync: REF SyncRec] ~ { ENABLE UNWIND => NULL; IF sync.jobCount > sync.JobLim THEN ERROR; WHILE sync.jobCount >= sync.JobLim AND ~sync.abortParent DO WAIT sync.QChange ENDLOOP; IF sync.abortParent THEN ERROR ABORTED; sync.jobCount _ sync.jobCount.SUCC }; Finished: ENTRY PROCEDURE [sync: REF SyncRec, readyQ: LIST OF REF Inversion, changed: BOOLEAN] ~ { ENABLE UNWIND => NULL; thisJob: REF Inversion ~ readyQ.first; IF changed THEN { sync.jobCount _ sync.jobCount.PRED; IF sync.jobCount < 0 THEN ERROR; BROADCAST sync.QChange }; FOR p: LIST OF REF Inversion _ thisJob.parents, p.rest WHILE p # NIL DO IF p.first.cell # NIL THEN { IF changed THEN CDProperties.PutPropOnObject[onto~ p.first.cell, prop~ SpinifexAtoms.spinifex] ELSE { cell: REF LogicalCell ~ NARROW[thisJob.data]; pCir: REF SpinifexCircuit.Circuit ~ NARROW[CDProperties.GetPropFromObject[from~ p.first.cell, prop~ SpinifexAtoms.spinifex]]; IF pCir # NIL AND pCir.invocationKey # cell.circuit.invocationKey THEN CDProperties.PutPropOnObject[onto~ p.first.cell, prop~ SpinifexAtoms.spinifex] } }; IF p.first.childCount < 1 THEN ERROR; IF (p.first.childCount _ p.first.childCount.PRED) = 0 THEN { WHILE readyQ.rest # NIL DO readyQ _ readyQ.rest ENDLOOP; readyQ.rest _ CONS[p.first, readyQ.rest]; BROADCAST sync.QChange } ENDLOOP }; Next: ENTRY PROCEDURE [readyQ: LIST OF REF Inversion, sync: REF SyncRec] RETURNS [LIST OF REF Inversion]~ { ENABLE UNWIND => NULL; WHILE readyQ.rest = NIL AND ~sync.abortParent DO WAIT sync.QChange ENDLOOP; IF sync.abortParent THEN ERROR ABORTED; RETURN [IF readyQ.rest.first.cell = NIL THEN NIL ELSE readyQ.rest] }; debugStats: BOOLEAN _ FALSE; -- Use the interpreter to set this to TRUE. TotRec: TYPE ~ RECORD [ nCount: INT _ 0, apCount: INT _ 0, lCount: INT _ 0, anCount: INT _ 0, merges: INT _ 0, branchCount: INT _ 0, rectCount: INT _ 0, wordCount: INT _ 0, mergeWordCount: INT _ 0, objects: INT _ 0 ]; TotalStorageUsage: PROCEDURE [t: REF TotRec] ~ { stats: IO.STREAM ~ IO.ROS[]; IF debugStats THEN { stats.PutF[ "\n===== Total Storage =====\nWords=%g; Objects=%g; n=%g, ap=%g, l=%g, ", IO.int[t.wordCount], IO.int[t.objects], IO.int[t.nCount], IO.int[t.apCount], IO.int[t.lCount]]; stats.PutF[ "an=%g, merges=%g [%g:w]; b=%g; r=%g\n\n", IO.int[t.anCount], IO.int[t.merges], IO.int[t.mergeWordCount], IO.int[t.branchCount], IO.int[t.rectCount]]; } ELSE stats.PutF[ " Total (%g:w; %g:obj)\n", IO.int[t.wordCount], IO.int[t.objects]]; TerminalIO.WriteRope[stats.RopeFromROS[]] }; ReportStorageUsage: ENTRY PROCEDURE [stats: IO.STREAM, cir: REF SpinifexCircuit.Circuit, tot: REF TotRec] ~ { ENABLE UNWIND => NULL; DottedPairSize: INT ~ SIZE[LIST OF REF] + SIZE[REF]; nCount: INT _ 0; apCount: INT _ 0; lCount: INT _ 0; anCount: INT _ 0; merges: INT _ 0; branchCount: INT _ 0; rectCount: INT _ 0; wordCount: INT _ 0; mergeWordCount: INT _ 0; objects: INT _ 0; wordCount _ wordCount + SIZE[SpinifexCircuit.Circuit]; FOR n: LIST OF REF SpinifexCircuit.CircuitNode _ cir.nodes, n.rest WHILE n # NIL DO nCount _ nCount.SUCC; FOR ap: LIST OF SpinifexCircuit.AreaPerimRec _ n.first.dim, ap.rest WHILE ap # NIL DO apCount _ apCount.SUCC ENDLOOP ENDLOOP; objects _ objects + nCount*2 + apCount; wordCount _ wordCount + nCount * (DottedPairSize + SIZE[SpinifexCircuit.CircuitNode]) + apCount * SIZE[LIST OF SpinifexCircuit.AreaPerimRec]; FOR l: LIST OF REF SpinifexCircuit.NodeLinkage _ cir.linkages, l.rest WHILE l # NIL DO lCount _ lCount.SUCC; FOR an: LIST OF REF SpinifexCircuit.AttachedNode _ l.first.nodes, an.rest WHILE an # NIL DO anCount _ anCount.SUCC ENDLOOP ENDLOOP; objects _ objects + lCount*2 + anCount; wordCount _ wordCount + lCount*(DottedPairSize+SIZE[SpinifexCircuit.NodeLinkage]) + anCount*SIZE[SpinifexCircuit.AttachedNode]; IF cir.mergeDirectory # NIL THEN { CountMergeDir: RefTab.EachPairAction -- [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOLEAN] -- ~ { FOR ml: SpinifexCircuit.MergeRecList _ NARROW[val], ml.rest WHILE ml # NIL DO applChainLength: CARDINAL _ 0; FOR aList: LIST OF CD.ApplicationPtr _ ml.first.applChain, aList.rest WHILE aList # NIL DO applChainLength _ applChainLength.SUCC ENDLOOP; objects _ objects + applChainLength; mergeWordCount _ mergeWordCount + DottedPairSize + SIZE[SpinifexCircuit.MergeRec] + applChainLength*DottedPairSize ENDLOOP; quit _ FALSE }; merges _ cir.mergeDirectory.GetSize[]; mergeWordCount _ mergeWordCount + 17*2 + merges*6; [] _ cir.mergeDirectory.Pairs[CountMergeDir]; wordCount _ wordCount + mergeWordCount -- Approximate! }; FOR layer: SpinifexCircuit.SpinifexLayerIndex IN [0..cir.technologyHandle.numSpinifexLayers) DO CountTree: PROCEDURE [qt: REF SpinifexCircuit.QuadTree] RETURNS [branches: INT _ 0, rects: INT _ 0] ~ { IF qt = NIL THEN RETURN; branches _ 1; FOR r: LIST OF REF SpinifexCircuit.Rectangle _ qt.boxes, r.rest WHILE r # NIL DO rects _ rects.SUCC ENDLOOP; FOR quad: SpinifexCircuit.AreaSplit IN SpinifexCircuit.AreaSplit DO subBranches: INT; subRects: INT; [subBranches, subRects] _ CountTree[qt.subTrees[quad]]; branches _ branches + subBranches; rects _ rects + subRects ENDLOOP }; layerBranches: INT; layerRects: INT; [layerBranches, layerRects] _ CountTree[cir.spinifexLayers[layer].geometry]; branchCount _ branchCount + layerBranches; rectCount _ rectCount + layerRects ENDLOOP; objects _ objects + rectCount*2 + branchCount; wordCount _ wordCount + rectCount*(DottedPairSize + SIZE[SpinifexCircuit.Rectangle]) + branchCount*SIZE[SpinifexCircuit.QuadTree]; tot.nCount _ tot.nCount + nCount; tot.apCount _ tot.apCount + apCount; tot.lCount _ tot.lCount + lCount; tot.anCount _ tot.anCount + anCount; tot.merges _ tot.merges + merges; tot.branchCount _ tot.branchCount + branchCount; tot.rectCount _ tot.rectCount + rectCount; tot.wordCount _ tot.wordCount + wordCount; tot.mergeWordCount _ tot.mergeWordCount + mergeWordCount; tot.objects _ tot.objects + objects; IF debugStats THEN { stats.PutF[ "\n{Words=%g; Objects=%g; n=%g, ap=%g, l=%g, ", IO.int[wordCount], IO.int[objects], IO.int[nCount], IO.int[apCount], IO.int[lCount]]; stats.PutF[ "an=%g, merges=%g [%g:w]; b=%g; r=%g}", IO.int[anCount], IO.int[merges], IO.int[mergeWordCount], IO.int[branchCount], IO.int[rectCount]]; } ELSE stats.PutF[ "(%g:w; %g:obj)", IO.int[wordCount], IO.int[objects]] }; END. žSpinifexAccessImpl.mesa Copyright c 1984 by Xerox Corporation. All rights reserved. Written by Shand, September 12, 1983 11:40 pm Last Edited by: Shand, September 3, 1984 3:24:04 am PDT -- Check that this technology can be analyzed. -- Check that specified cells can act as roots for analysis. -- Lock cell and subcells for duration of analysis. -- Sequence through cells. Inversion routine returns cells whose ordering is the partial ordering induced by the cell hierarchy. Last item in ordering is the hierarchy root. Transfer completed cell to done list and move to next cell to jobQ -- Cell hierarchy is now extracted. -- Output results of extraction. -- Release Locks. UnlockCells[done]; -- Add $Spinifex data-structure to cell object properties. Check a subcell has not been re-analyzed without its parent being analyzed -- Statistics. Nodes. Linkages. Merge Directory. Geometry. Sum totals. Output Statistics. Κ$˜codešœ™Kšœ Οmœ1™