<> <> <> <> <> DIRECTORY Atom USING [GetPName], CD USING [InstanceList, Object, Rect], CDBasics USING [Extend], CDBottomUp USING [Class, DoProc, DoRecurse, Handle, MakeHandle, Register, ReUseProc], CDDirectory USING [Name], CDErrors USING [IncludeMessage, RemoveMessages], CDEvents USING [EventProc, RegisterEventProc], CDOps USING [ObjectInfo], CDProperties USING [GetObjectProp, PutObjectProp], CDSequencer USING [], IO USING [int, PutFR, rope], Rope USING [Cat, Concat, IsEmpty, ROPE], SX USING [Circuit, LogicalCell, TranslateGeometry], SXAccess USING [design, formatKey, invocation, stopFlag, sxTech], SXAccessInternal USING [], SXAtoms USING [spinifexCircuitDescription], SXLayers USING [AnalyzeGeometry], SXOutput USING [PrintCircuit], SXUserExtract USING [TranslateCell], TerminalIO USING [WriteLn, WriteRope]; SXAccessInternalImpl: CEDAR PROGRAM IMPORTS Atom, CDBasics, CDBottomUp, CDDirectory, CDErrors, CDEvents, CDOps, CDProperties, IO, Rope, SX, SXAccess, SXAtoms, SXLayers, SXOutput, SXUserExtract, TerminalIO EXPORTS SXAccessInternal = BEGIN debug: BOOL _ FALSE; LogicalCell: TYPE = SX.LogicalCell; DoneList: TYPE = LIST OF REF LogicalCell; errorSummary: LIST OF Rope.ROPE _ NIL; doneList: DoneList; 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 PrintDoneList: PROC ~ BEGIN <> TerminalIO.WriteRope ["\nDone list: "]; FOR l: DoneList _ doneList, l.rest WHILE l # NIL DO TerminalIO.WriteRope [CDOps.ObjectInfo[l.first.cellObj]]; TerminalIO.WriteRope [", "] ENDLOOP; TerminalIO.WriteRope ["\n"] END; -- PrintDoneList GetLogicalCell: PUBLIC PROC [ob: CD.Object] RETURNS [REF LogicalCell] = BEGIN IF ~ob.class.inDirectory THEN RETURN [NIL]; WITH CDProperties.GetObjectProp [ob, $SX] SELECT FROM sxd: REF LogicalCell => RETURN [sxd]; ENDCASE => { sxd: REF LogicalCell _ NEW [LogicalCell]; sxd.analysisState _ notYetDone; -- redundant sxd.cellObj _ ob; -- WOULD BE BETTER TO AVOID THIS CIRCULARITY ! CDProperties.PutObjectProp [onto: ob, prop: $SX, val: sxd]; RETURN [sxd] } END; -- GetLogicalCell DistroyLogicalCell: CDEvents.EventProc = BEGIN <<[event: REF, design: CD.Design, x: REF] RETURNS [dont: BOOL_FALSE]>> <> cell: CD.Object = NARROW [x, CD.Object]; CDProperties.PutObjectProp [onto: cell, prop: $SX, val: NIL] END; -- DistroyLogicalCell Analyze: PUBLIC PROC [hierarchyRoots: CD.InstanceList] = BEGIN MarkAndCheckRoots: PROC [hierarchyRoots: CD.InstanceList] RETURNS [roots: CD.InstanceList_NIL] = BEGIN FOR al: CD.InstanceList _ hierarchyRoots, al.rest WHILE al#NIL DO IF al.first.ob.class.inDirectory THEN { lc: REF LogicalCell = GetLogicalCell [al.first.ob]; lc.rootOnInvocation _ SXAccess.invocation; roots _ CONS [al.first, roots]; } ELSE TerminalIO.WriteRope [IO.PutFR["*** %g cannot be root of analysis.\n", IO.rope[CDOps.ObjectInfo[al.first.ob]]]]; ENDLOOP END; -- MarkAndCheckRoots AnalyzeEach: PROC [hierarchyRoots: CD.InstanceList ] = BEGIN h: CDBottomUp.Handle _ CDBottomUp.MakeHandle [spinifex, SXAccess.design]; FOR al: CD.InstanceList _ hierarchyRoots, al.rest WHILE al#NIL DO [] _ CDBottomUp.DoRecurse [h, 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 <
> errorSummary _ NIL; doneList _ NIL; IF debug THEN TerminalIO.WriteRope ["doneList _ NIL\n"]; hierarchyRoots _ MarkAndCheckRoots [hierarchyRoots]; AnalyzeEach [hierarchyRoots]; IF debug THEN PrintDoneList []; WriteErrorSummary []; IF (doneList # NIL) AND (SXAccess.formatKey # NIL) THEN SXOutput.PrintCircuit [InvertList[doneList], SXAccess.formatKey] END; -- Analyze DoProc: CDBottomUp.DoProc = BEGIN lc: REF LogicalCell = GetLogicalCell [ob]; CDErrors.RemoveMessages [design: SXAccess.design, ob: ob, owner: $SXErrorMessage]; AnalyzePreparedOb [ob]; lc.lastInvocation _ SXAccess.invocation END; -- DoProc ReUseProc: CDBottomUp.ReUseProc = BEGIN cell: REF LogicalCell = GetLogicalCell [ob]; doneList _ CONS [cell, doneList]; TerminalIO.WriteRope [IO.PutFR ["skipped: %g, already analyzed.", IO.rope[CDDirectory.Name[ob]]]]; WriteDevices [cell]; WriteErrors [cell]; TerminalIO.WriteLn []; cell.lastInvocation _ SXAccess.invocation; END; -- ReUseProc WriteErrors: PROC [lc: REF LogicalCell] = BEGIN IF lc.errorCount#0 THEN { message: Rope.ROPE _ IO.PutFR[" %g errors", IO.int[lc.errorCount]]; IF ~Rope.IsEmpty[lc.errorContext] THEN message _ Rope.Cat [message, " displayed in ", lc.errorContext]; TerminalIO.WriteRope [Rope.Concat ["; ", message]]; errorSummary _ CONS [Rope.Concat[CDDirectory.Name[lc.cellObj], message], errorSummary] } END; -- WriteErrors WriteDevices: PROC [lc: REF LogicalCell] = BEGIN TerminalIO.WriteRope [IO.PutFR [" %g/%g transistors.", IO.int [lc.circuit.linkageCount.inSelf+lc.circuit.linkageCount.inChildren], IO.int [lc.circuit.linkageCount.inSelf]]]; END; -- WriteDevices SkipAnalyzedOb: PROC [ob: CD.Object, lc: REF LogicalCell] = BEGIN cell: REF LogicalCell = GetLogicalCell [ob]; doneList _ CONS [cell, doneList]; TerminalIO.WriteRope [IO.PutFR ["skipped: %g, already analyzed.", IO.rope[CDDirectory.Name[ob]]]]; WriteDevices[lc]; WriteErrors[lc]; TerminalIO.WriteLn[] END; -- SkipAnalyzedOb AnalyzePreparedOb: PUBLIC PROC [ob: CD.Object] = BEGIN cell: REF LogicalCell = GetLogicalCell [ob]; opaque: REF = CDProperties.GetObjectProp [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; <> 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.Object, key: REF] = BEGIN cell: REF LogicalCell = GetLogicalCell [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.Object, r: CD.Rect, message: Rope.ROPE] = BEGIN lc: REF LogicalCell = GetLogicalCell [ob]; done: BOOL = CDErrors.IncludeMessage [design: SXAccess.design, ob: ob, rect: CDBasics.Extend [r, SXAccess.design.technology.lambda/2], message: message, owner: $SXErrorMessage].done; IF lc#NIL THEN { lc.errorCount _ lc.errorCount + 1; IF (lc.errorCount < 10) THEN TerminalIO.WriteRope ["|"]; }; IF ~done THEN TerminalIO.WriteRope [Rope.Cat ["** unable to place error message ", message, ".\n"]]; END; -- PutError spinifex: CDBottomUp.Class = CDBottomUp.Register [DoProc, ReUseProc]; CDEvents.RegisterEventProc [proc: DistroyLogicalCell, event: $AfterCellReplacement]; CDEvents.RegisterEventProc [proc: DistroyLogicalCell, event: $AfterChange]; END. <> <> <> <> <> <> <> <> <<>> <<>>