SpinifexAccessImpl.mesa
Copyright © 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
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: BOOLEANTRUE; -- 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[];
-- Check that this technology can be analyzed.
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
};
-- Check that specified cells can act as roots for analysis.
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;
-- Lock cell and subcells for duration of analysis.
ready ← SpinifexInvert.Invert[design, hierarchyRoots, NewLogicalCell];
done ← NIL;
TerminalIO.WriteRope["Hierarchy processing order determined\n"];
-- 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.
{
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]] }
};
Transfer completed cell to done list and move to next cell to jobQ
doneTail.rest ← CONS[ NARROW[jobQ.first.data], NIL];
doneTail ← doneTail.rest;
jobQ ← Next[jobQ, sync];
ENDLOOP;
TotalStorageUsage[sync.totals]; -- Development statistics.
done ← done.rest
};
-- Cell hierarchy is now extracted.
CornerStitching.DumpCache[];
TerminalIO.WriteRope[ IO.PutFR["Elapsed time = %gs\n", IO.int[ BasicTime.Period[ from~ startTime, to~ BasicTime.Now[]]] ]];
-- Output results of extraction.
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[]]] ]]
};
-- Release Locks.
UnlockCells[done];
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];
-- Add $Spinifex data-structure to cell object properties.
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: BOOLEANFALSE
];
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 {
Check a subcell has not been re-analyzed without its parent being analyzed
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]
};
-- Statistics.
debugStats: BOOLEANFALSE; -- 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];
Nodes.
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];
Linkages.
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];
Merge Directory.
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!
};
Geometry.
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];
Sum totals.
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;
Output Statistics.
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.