SXAccessInternalImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Written by Jacobi, April 2, 1985 5:11:35 pm PST
Last Edited by: Jacobi, April 2, 1985 5:11:39 pm PST
Last Edited by: Beretta, July 3, 1985 3:11:06 pm PDT
DIRECTORY
Atom,
CD,
CDBasics,
CDDirectory,
CDErrors,
CDEvents,
CDOps,
CDProperties,
CDSequencer,
IO,
Rope,
SX,
SXAccess,
SXAccessInternal,
SXAtoms,
SXLayers,
SXOutput,
SXUserExtract,
TerminalIO;
SXAccessInternalImpl: CEDAR PROGRAM
IMPORTS Atom, CDBasics, CDDirectory, CDErrors, CDEvents, CDOps, CDProperties, IO, Rope, SX, SXAccess, SXAtoms, SXLayers, SXOutput, SXUserExtract, TerminalIO
EXPORTS SXAccessInternal =
BEGIN
SXData: TYPE = SX.LogicalCell;
DoneList: TYPE = LIST OF REF SXData;
errorSummary: LIST OF Rope.ROPENIL;
doneList: DoneList;
changedList: LIST OF CD.ObPtr ← NIL;
InvertList: PROC [old: DoneList] RETURNS [new: DoneList←NIL] =
BEGIN
FOR list: DoneList ← old, list.rest WHILE list#NIL DO
new ← CONS [list.first, new]
ENDLOOP;
END; -- InvertList
CleanUpDoneList: PROCEDURE [dirty: DoneList] RETURNS [clean: DoneList ← NIL] =
When a cell is edited and replaced, it gets into the doneList. This procedure removes the old logical cell associated with this cell.
BEGIN
FOR cells: DoneList ← doneList, cells.rest WHILE cells # NIL DO
notObsolete: BOOLTRUE;
FOR cadavers: LIST OF CD.ObPtr ← changedList, cadavers.rest WHILE cadavers # NIL DO
IF cells.first.cellObj = cadavers.first THEN notObsolete ← FALSE
ENDLOOP;
IF notObsolete THEN clean ← CONS [cells.first, clean]
ENDLOOP;
clean ← InvertList [clean]; changedList ← NIL
END; -- CleanUpDoneList
GetSXData: PUBLIC PROC[ob: CD.ObPtr] RETURNS [REF SXData] =
BEGIN
IF ~ob.p.inDirectory THEN RETURN [NIL];
WITH CDProperties.GetPropFromObject [ob, $SX] SELECT FROM
sxd: REF SXData => RETURN [sxd];
ENDCASE => {
sxd: REF SXData ← NEW[SXData];
sxd.analysisState ← notYetDone; -- redundant
sxd.cellObj ← ob; --WOULD BE BETTER TO AVOID THIS CIRCULARITY !
CDProperties.PutPropOnObject [onto: ob, prop: $SX, val: sxd];
RETURN [sxd]
};
END; -- GetSXData
ClearSXData: CDEvents.EventProc =
--PROC [event: REF, design: CD.Design, x: REF] RETURNS [dont: BOOL�LSE]
BEGIN
cell: CD.ObPtr = NARROW [x, CD.ObPtr];
changedList ← CONS [cell, changedList];
CDProperties.PutPropOnObject [onto: cell, prop: $SX, val: NIL];
END; -- ClearSXData
Analyze: PUBLIC PROC [hierarchyRoots: CD.ApplicationList] =
BEGIN
MarkAndCheckRoots: PROC [hierarchyRoots: CD.ApplicationList]
RETURNS [roots: CD.ApplicationList←NIL] =
BEGIN
FOR al: CD.ApplicationList ← hierarchyRoots, al.rest WHILE al#NIL DO
IF al.first.ob.p.inDirectory THEN {
sx: REF SXData = GetSXData[al.first.ob];
sx.rootOnInvocation ← SXAccess.invocation;
roots ← CONS[al.first, roots];
}
ELSE TerminalIO.WriteRope
[IO.PutFR["** %g cannot be root of analysis\n", IO.rope[CDOps.Info[al.first.ob]]]];
ENDLOOP;
END; -- MarkAndCheckRoots
AnalyzeEach: PROC [hierarchyRoots: CD.ApplicationList ] =
BEGIN
FOR al: CD.ApplicationList ← hierarchyRoots, al.rest WHILE al#NIL DO
[] ← AnalyzeObAndChildren[al.first.ob]
ENDLOOP
END; -- AnalyzeEach
WriteErrorSummary: PROC [] =
BEGIN
IF errorSummary=NIL THEN TerminalIO.WriteRope["no errors\n"]
ELSE {
TerminalIO.WriteRope["Summary of DRC errors:\n"];
FOR list: LIST OF Rope.ROPE ← errorSummary, list.rest WHILE list#NIL DO
TerminalIO.WriteRope[" "];
TerminalIO.WriteRope[list.first];
TerminalIO.WriteLn[];
ENDLOOP
};
END; -- WriteErrorSummary
Main of Analyze
errorSummary ← NIL;
doneList ← CleanUpDoneList [doneList];
hierarchyRoots ← MarkAndCheckRoots[hierarchyRoots];
AnalyzeEach[hierarchyRoots];
WriteErrorSummary[];
SXOutput.PrintCircuit [InvertList[doneList], SXAccess.formatKey]
END; -- Analyze
AnalyzeObAndChildren: PROC [ob: CD.ObPtr]
RETURNS [propagate: BOOLFALSE] =
BEGIN
CheckAChild: CDDirectory.EnumerateObjectsProc =
--PROC [me: CD.ObPtr, x: REF]
--figures out if we need to reanalyze AnalyzeObAndChildren.ob because me changed
BEGIN
childPropagates: BOOL ← AnalyzeObAndChildren[me];
propagate ← propagate OR childPropagates;
END; -- CheckAChild
sx: REF SXData = GetSXData[ob];
IF sx#NIL AND (sx.lastInvocation#SXAccess.invocation OR sx.analysisState=notYetDone) THEN {
propagate ← sx.analysisState=notYetDone;
CDDirectory.EnumerateChildObjects[me: ob, p: CheckAChild, x: NIL];
IF propagate THEN-- analyze object
BEGIN
CDErrors.RemoveMessages [design: SXAccess.design, ob: ob, owner: $SXErrorMessage];
AnalyzePreparedOb [ob]
END
ELSE
SkipAnalyzedOb[ob, sx];
sx.lastInvocation ← SXAccess.invocation;
};
END; -- AnalyzeObAndChildren
WriteErrors: PROC [sx: REF SXData] =
BEGIN
IF sx.errorCount#0 THEN {
message: Rope.ROPEIO.PutFR[" %g errors", IO.int[sx.errorCount]];
IF ~Rope.IsEmpty[sx.errorContext] THEN
message ← Rope.Cat[message, " displayed in ", sx.errorContext];
TerminalIO.WriteRope[";"];
TerminalIO.WriteRope[message];
errorSummary ← CONS[Rope.Concat[CDDirectory.Name[sx.cellObj], message], errorSummary]
}
END; -- WriteErrors
WriteDevices: PROC [sx: REF SXData] =
BEGIN
TerminalIO.WriteRope[IO.PutFR["; %g/%g transistors",
IO.int[sx.circuit.linkageCount.inSelf+sx.circuit.linkageCount.inChildren],
IO.int[sx.circuit.linkageCount.inSelf]
]];
END; -- WriteDevices
SkipAnalyzedOb: PROC [ob: CD.ObPtr, sx: REF SXData] =
BEGIN
TerminalIO.WriteRope[IO.PutFR["skipped: %g, already analyzed",
IO.rope[CDDirectory.Name[ob]]
]];
WriteDevices[sx];
WriteErrors[sx];
TerminalIO.WriteLn[];
END;
AnalyzePreparedOb: PUBLIC PROC [ob: CD.ObPtr] =
BEGIN
cell: REF SX.LogicalCell = GetSXData[ob];
opaque: REF = CDProperties.GetPropFromObject[ob, SXAtoms.spinifexCircuitDescription];
cell.circuit ← NEW[SX.Circuit];
IF opaque#NIL THEN AnalyzeOpaqueOb[ob, opaque]
ELSE {
TerminalIO.WriteRope[Rope.Cat["analyzing: """, CDDirectory.Name[cell.cellObj], """"]];
IF SXAccess.stopFlag^ THEN ERROR ABORTED;
SX.TranslateGeometry[cell];
TerminalIO.WriteRope[". "];
IF SXAccess.stopFlag^ THEN ERROR ABORTED;
SXLayers.AnalyzeGeometry[cell];
IF SXAccess.stopFlag^ THEN ERROR ABORTED;
--Technology dependent manipulation and checking (e.g. CMOS n-well connects).
IF SXAccess.sxTech.cellPostProcess#NIL THEN SXAccess.sxTech.cellPostProcess[cell];
};
doneList ← CONS[cell, doneList];
WriteDevices[cell];
WriteErrors[cell];
TerminalIO.WriteLn[];
cell.analysisState ← useCircuit;
END; -- AnalyzePreparedOb
AnalyzeOpaqueOb: PUBLIC PROC [ob: CD.ObPtr, key: REF] =
BEGIN
cell: REF SX.LogicalCell = GetSXData[ob];
WITH key SELECT FROM
cirDesc: Rope.ROPE => {
TerminalIO.WriteRope[Rope.Cat["processing user circuit description: """, CDDirectory.Name[cell.cellObj], """"]];
SXUserExtract.TranslateCell[cell, cirDesc];
};
ENDCASE => {
TerminalIO.WriteRope[Rope.Cat["$", Atom.GetPName[SXAtoms.spinifexCircuitDescription], "property of cell " , CDDirectory.Name[ob], " not a rope\n"]];
ERROR ABORTED
};
END; -- AnalyzeOpaqueOb
PutError: PUBLIC PROC [ob: CD.ObPtr, r: CD.DesignRect, message: Rope.ROPE] =
BEGIN
sx: REF SXData = GetSXData[ob];
done: BOOL = CDErrors.IncludeMessage[
design: SXAccess.design,
ob: ob,
rect: CDBasics.Extend[r, CD.lambda/2],
message: message,
owner: $SXErrorMessage].done;
IF sx#NIL THEN {
sx.errorCount ← sx.errorCount + 1;
IF sx.errorCount<10 THEN TerminalIO.WriteRope["|"];
};
IF ~done THEN {
TerminalIO.WriteRope["** unable to place error message "];
TerminalIO.WriteRope[message];
TerminalIO.WriteLn[];
};
END; -- PutError
CDEvents.RegisterEventProc [proc: ClearSXData, event: $AfterCellReplacement];
CDEvents.RegisterEventProc [proc: ClearSXData, event: $AfterChange];
END.
Edited on June 18, 1985 6:04:15 pm PDT, by Beretta
done list of logicall cells is inverted before output is produced, because Thyme requires circuits to be declared before they are referenced.
changes to: InvertList: new, Analyze: SXOutput.PrintCircuit is called with inverted list.
Edited on July 3, 1985 3:11:06 pm PDT, by Beretta
Introduced a changedList into which ChipNDale keeps track of changed cells. When Spinifex is invocated it first removes the cadavers form the doneList.
changes to: DoneList: new type, changedList: holds the pointers to the changed cells, CleanUpDoneList: removes the cadavers, ClearSXData: updates the changedList, Analyze: calls CleanUpDoneList, CleanUpDoneList