<> <> <> <> <> <> <> <> <> DIRECTORY Atom USING [GetPName], Basics USING [CompareInt, Comparison], CD, CDInstances, CDBasics, CDOps USING [LayerRope], CDProperties USING [DCopyProps, GetProp, GetInstanceProp, GetListProp, PutInstanceProp], Convert USING [RopeFromInt], Properties USING [GetProp, PropList, PutProp], RedBlackTree USING [Compare, Create, DuplicateKey, GetKey, Insert, LookupNextLarger, LookupSmallest, Table], RefTab USING [Create, EachPairAction, Fetch, GetSize, Insert, Pairs, Ref, Store], Rope USING [Cat, FromRefText, Equal, ROPE], SX USING [AdjustmentMode, AreaPerimRec, AttachedNode, BoxMapProc, Circuit, CircuitNode, Constraint, ConversionProc, LogicalCell, MapRec, MergeRec, MergeRecList, NodeLinkage, SignalName, SpinifexLayerIndex], SXAccess USING [stopFlag, sxTech], SXAccessInternal USING [GetLogicalCell, PutError], SXAtoms USING [export, InstanceName, Rect, SignalName, spinifex], SXQuadTree USING [AreaSplit, Store, QuadTree, QuadTreeRoot, Rectangle, RectDelta]; SXImpl: CEDAR PROGRAM IMPORTS Atom, Basics, CD, CDInstances, CDBasics, CDOps, CDProperties, Convert, Properties, RedBlackTree, RefTab, Rope, SXAccess, SXAccessInternal, SXAtoms, SXQuadTree EXPORTS SX = BEGIN <> AreaPerimRec: TYPE = SX.AreaPerimRec; AttachedNode: TYPE = SX.AttachedNode; Circuit: TYPE = SX.Circuit; Constraint: TYPE = SX.Constraint; LogicalCell: TYPE = SX.LogicalCell; MapRec: TYPE = SX.MapRec; MergeRec: TYPE = SX.MergeRec; NodeLinkage: TYPE = SX.NodeLinkage; SignalName: TYPE = SX.SignalName; SpinifexLayerIndex: TYPE = SX.SpinifexLayerIndex; <> IllegalConstruct: PUBLIC ERROR [rect: CD.Rect, reason: Rope.ROPE] = CODE; IllegalLayer: PUBLIC ERROR [rect: CD.Rect, lev: CD.Layer] = CODE; specialLayers: CD.Layer = MAX [CD.shadeLayer, CD.errorLayer, CD.backgroundLayer, CD.outlineLayer, CD.selectionLayer, CD.commentLayer]; repetitionInstanceNamePrefix: Rope.ROPE _ ""; repetitionInstanceNamePostfix: Rope.ROPE _ ""; IsSimpleRect: PROC [ob: CD.Object] RETURNS [BOOL] = INLINE BEGIN RETURN [ob.class.objectType = SXAtoms.Rect] END; -- IsSimpleRect TranslateChild: CD.DrawProc = BEGIN sxThrough: REF LogicalCell = NARROW [pr.devicePrivate]; cir: REF Circuit = sxThrough.circuit; IF ob.class.symbolic THEN RETURN; IF IsSimpleRect[ob] THEN { IF ob.layer > specialLayers THEN { node: REF SX.CircuitNode = AddRect [cir: cir, lev: ob.layer, dim: ob.bbox, trans: trans ! IllegalLayer => { SXAccessInternal.PutError[sxThrough.cellObj, rect, Rope.Cat["material on layer ", CDOps.LayerRope[lev], " must not appear as isolated rectangles.\n"]]; GOTO BadRect } ]; IF node # NIL THEN CopyNodeProperties [cir, node, readOnlyInstProps]; EXITS BadRect => NULL }; RETURN } -- end simple rectangle. ELSE { sx: REF LogicalCell _ SXAccessInternal.GetLogicalCell [ob]; IF (sx # NIL) AND (sx.analysisState = useCircuit) THEN { <<--This object is a logical subcircuit.>> subcircuit: REF Circuit = sx.circuit; myInst: CD.Instance = NEW [CD.InstanceRep _ [ob: ob, trans: trans, properties: CDProperties.DCopyProps [propList: readOnlyInstProps]]]; FOR i: SpinifexLayerIndex IN [0..SXAccess.sxTech.numSpinifexLayers) DO IF subcircuit.spinifexLayers[i].private # NIL THEN { IF (cir.subcircuits = NIL) OR (cir.subcircuits.first # myInst) THEN { <<--It is the 1st non-empty geom-layer.>> cir.subcircuits _ CONS [myInst, cir.subcircuits]; }; [] _ AddBox [cir: cir, trans: trans, spinifexLayer: i, dim: subcircuit.spinifexLayers[i].size, value: myInst]; } ENDLOOP; cir.linkageCount.inChildren _ cir.linkageCount.inChildren + subcircuit.linkageCount.inSelf + subcircuit.linkageCount.inChildren; } ELSE { -- expand special objects (transistors) and conditional objects WITH CDProperties.GetProp [from: ob.class.properties, prop: SXAtoms.spinifex] SELECT FROM convProc: REF SX.ConversionProc => convProc^[ob, trans, cir ! IllegalConstruct => { SXAccessInternal.PutError [sxThrough.cellObj, CDBasics.MapRect[itemInCell: rect, cellInWorld: trans], reason]; CONTINUE} ]; ENDCASE => ob.class.drawMe[pr, ob, trans, readOnlyInstProps]-- analysis state: notYetDone } } END; -- TranslateChild TranslateRect: CD.DrawRectProc = BEGIN IF CDBasics.NonEmpty[r] AND l # CD.errorLayer THEN { sxc: REF LogicalCell = NARROW [pr.devicePrivate]; [] _ AddRect [cir: sxc.circuit, lev: l, dim: r ! IllegalLayer => { SXAccessInternal.PutError [sxc.cellObj, rect, Rope.Cat ["rectangle on layer ", CDOps.LayerRope [lev], " cannot be analyzed in this context.\n"]]; CONTINUE} ] } END; <<>> <> SKey: TYPE = REF CD.Position; -- RedBlackTree.Key SRec: TYPE = RECORD [key: SKey, instance: CD.Instance]; SData: TYPE = REF SRec; -- RedBlackTree.UserData InstKey: RedBlackTree.GetKey = BEGIN RETURN [NARROW [data, SData].key] END; -- InstKey InstComp: RedBlackTree.Compare = BEGIN c: Basics.Comparison; sk: SKey = NARROW [k]; d: SData = NARROW [data]; c _ Basics.CompareInt [sk.x, d.key.x]; IF c = equal THEN c _ Basics.CompareInt [sk.y, d.key.y]; RETURN [c] END; -- InstComp SInsert: PROCEDURE [s: RedBlackTree.Table, inst: CD.Instance] RETURNS [duplicate: BOOL] = BEGIN ENABLE RedBlackTree.DuplicateKey => GOTO dupl; sk: SKey _ NEW [CD.Position _ CDBasics.BaseOfRect[CDInstances.InstRectO[inst]]]; data: SData _ NEW [SRec _ [key: sk, instance: inst]]; RedBlackTree.Insert [s, data, sk]; <> RETURN [FALSE]; EXITS dupl => RETURN [TRUE] END; -- SInsert <<>> PutInstanceNamesIfRepetition: PROC [cir: REF Circuit] = { IF cir.subcircuits#NIL AND cir.subcircuits.rest#NIL AND cir.subcircuits.rest.rest#NIL THEN BEGIN <> FOR sub: CD.InstanceList _ cir.subcircuits, sub.rest WHILE sub#NIL DO IF cir.subcircuits.first.trans.orient # sub.first.trans.orient THEN EXIT; IF cir.subcircuits.first.ob # sub.first.ob THEN EXIT; REPEAT FINISHED => BEGIN <> sTab: RedBlackTree.Table = RedBlackTree.Create [InstKey, InstComp]; lastApp, currApp: SData; delta: CD.Position; FOR sub: CD.InstanceList _ cir.subcircuits, sub.rest WHILE sub#NIL DO IF SInsert [sTab, sub.first] THEN GOTO EqualAppls; ENDLOOP; lastApp _ NARROW [RedBlackTree.LookupSmallest[sTab]]; currApp _ NARROW [RedBlackTree.LookupNextLarger[sTab,lastApp.key]]; delta _ CDBasics.SubPoints[currApp.instance.trans.off, lastApp.instance.trans.off]; lastApp _ currApp; WHILE (currApp _ NARROW[RedBlackTree.LookupNextLarger[sTab, lastApp.key]]) # NIL DO IF delta # CDBasics.SubPoints[currApp.instance.trans.off, lastApp.instance.trans.off] THEN EXIT; lastApp _ currApp; REPEAT FINISHED => BEGIN <> index: INT _ 1; FOR a: SData _ NARROW[RedBlackTree.LookupSmallest[sTab]], NARROW[RedBlackTree.LookupNextLarger[sTab, a.key]] WHILE a # NIL DO IF CDProperties.GetInstanceProp[from: a.instance, prop: SXAtoms.InstanceName]=NIL THEN BEGIN <> <> <> instanceName: Rope.ROPE _ repetitionInstanceNamePrefix.Cat[Convert.RopeFromInt[index], repetitionInstanceNamePostfix]; CDProperties.PutInstanceProp [a.instance, SXAtoms.InstanceName, instanceName]; END; index _ index+1 ENDLOOP END; ENDLOOP; EXITS EqualAppls => NULL END ENDLOOP; END }; sxContextFilter: REF CD.ContextFilter; TranslateGeometry: PUBLIC PROC [cell: REF LogicalCell] = BEGIN <> cir: REF Circuit = cell.circuit; dr: CD.DrawRef = CD.CreateDrawRef [[ drawRect: TranslateRect, drawChild: TranslateChild, devicePrivate: cell, contextFilter: sxContextFilter, stopFlag: SXAccess.stopFlag ]]; CD.DrawOb[dr, cell.cellObj]; <<--count devices>> FOR link: LIST OF REF NodeLinkage _ cir.linkages, link.rest WHILE link#NIL DO cir.linkageCount.inSelf _ cir.linkageCount.inSelf + 1 ENDLOOP; PutInstanceNamesIfRepetition[cir]; END; UniformBloat: PROC [d: INT] RETURNS [SXQuadTree.RectDelta] = INLINE { RETURN [[d,d,d,d]] }; AddRect: PUBLIC PROC [ cir: REF Circuit, lev: CD.Layer, dim: CD.Rect, trans: CD.Transformation _ [], value: REF SX.CircuitNode _ NIL] RETURNS [cirNode: REF SX.CircuitNode _ NIL] = BEGIN IF SXAccess.sxTech.illegalLayer[lev] THEN ERROR IllegalLayer [CDBasics.MapRect [itemInCell: dim, cellInWorld: trans], lev]; IF CDBasics.NonEmpty[dim] THEN -- Silently ignore empty boxes FOR map: LIST OF MapRec _ SXAccess.sxTech.cdLayerMapping[lev], map.rest WHILE map#NIL DO cn: REF SX.CircuitNode; WITH map.first.value SELECT FROM mappingFunc: REF SX.BoxMapProc => cn _ mappingFunc^[ cir: cir, dim: dim, trans: trans, node: (IF cirNode#NIL THEN cirNode ELSE value)]; ENDCASE => cn _ AddBox [cir: cir, spinifexLayer: map.first.spinifexLayer, dim: dim, trans: trans, interestBloat: UniformBloat[map.first.bloatFactor], value: (IF map.first.value#NIL THEN map.first.value ELSE value)]; IF cn#NIL THEN cirNode _ cn ENDLOOP; END; -- AddRect AddEmptyBox: ERROR = CODE; AddBox: PUBLIC PROC [ cir: REF Circuit, spinifexLayer: SpinifexLayerIndex, dim: CD.Rect, trans: CD.Transformation _ [], interestBloat: SXQuadTree.RectDelta _ [0,0,0,0], value: REF ANY _ NIL] RETURNS [cirNode: REF SX.CircuitNode _ NIL] = BEGIN A: PROC [r: CD.Rect] RETURNS [area: INT] = INLINE BEGIN area _ (r.x2-r.x1) * (r.y2-r.y1) END; -- A P: PROC [r: CD.Rect] RETURNS [perim: INT] = INLINE BEGIN perim _ ((r.x2-r.x1) + (r.y2-r.y1)) * 2 END; -- P IF ~CDBasics.NonEmpty [dim] THEN ERROR AddEmptyBox ELSE { bloatedDim, bloatedMapped, mappedDim: CD.Rect; newRect: REF SXQuadTree.Rectangle; bloatedDim _ [x1: dim.x1-interestBloat.dx1, y1: dim.y1-interestBloat.dy1, x2: dim.x2+interestBloat.dx2, y2: dim.y2+interestBloat.dy2]; bloatedMapped _ CDBasics.MapRect [itemInCell: bloatedDim, cellInWorld: trans]; mappedDim _ CDBasics.MapRect [itemInCell: dim, cellInWorld: trans]; IF value = NIL THEN { value _ cirNode _ NEW [SX.CircuitNode _ [ dim: LIST[[layer: spinifexLayer, area: A[dim], perim: P[dim]]], loc: [CDBasics.Center[mappedDim], spinifexLayer] ]]; AddCircuitNode [cir, cirNode] } ELSE WITH value SELECT FROM cn: REF SX.CircuitNode => { cirNode _ cn; AdjustNode [cirNode, spinifexLayer, A[dim], P[dim]] }; ENDCASE => NULL; newRect _ NEW [SXQuadTree.Rectangle _ [ interestBound: bloatedMapped, dimDecr: [ dx1: mappedDim.x1-bloatedMapped.x1, dy1: mappedDim.y1-bloatedMapped.y1, dx2: bloatedMapped.x2-mappedDim.x2, dy2: bloatedMapped.y2-mappedDim.y2], nodeInformation: value ]]; cir.spinifexLayers[spinifexLayer] _ SXQuadTree.Store [quadTree: cir.spinifexLayers[spinifexLayer], rect: newRect] } END; -- AddBox MergeNode: PUBLIC PROC [circuit: REF Circuit, to, from: REF SX.CircuitNode] = BEGIN <> IF from.superceded#NIL THEN from _ LookupNode [from]; IF to.superceded#NIL THEN to _ LookupNode [to]; IF from=to THEN RETURN; <> FOR fromList: LIST OF AreaPerimRec _ from.dim, fromList.rest WHILE fromList#NIL DO AdjustNode [to, fromList.first.layer, fromList.first.area, fromList.first.perim] ENDLOOP; <> CopyNodeProperties [circuit, to, from.properties]; from.properties _ NIL; from.superceded _ to END; -- MergeNode CopyNodeProperties: PROC [ circuit: REF Circuit, node: REF SX.CircuitNode, properties: Properties.PropList, qual: LIST OF CD.Instance _ NIL] = BEGIN CopySignal: PROC [sig: REF ANY, depth: INTEGER] RETURNS [REF SignalName] = BEGIN <> IF sig=NIL THEN RETURN [NIL]; WITH sig SELECT FROM r: Rope.ROPE => RETURN [NEW[SignalName _ [depth: depth, name: r]]]; t: REF TEXT => RETURN [NEW[SignalName _ [depth: depth, name: Rope.FromRefText[t]]]]; a: ATOM => RETURN [NEW[SignalName _ [depth: depth, name: Atom.GetPName[a]]]]; s: REF SignalName => BEGIN copyHead, copyTail: REF SignalName; copyHead _ NEW [SignalName _ [depth: s.depth+depth, name: s.name, makePort: s.makePort]]; copyTail _ copyHead; FOR source: REF SignalName _ s.alias, source.alias WHILE source#NIL DO copyTail.alias _ NEW [SignalName _ [depth: source.depth+depth, name: source.name]]; copyTail _ copyTail.alias; ENDLOOP; RETURN [copyHead]; END; ENDCASE => ERROR; END; -- CopySignal MergeAliases: PROC [to, from: REF SignalName] = BEGIN WHILE from # NIL DO FOR existingAlias: REF SignalName _ to, existingAlias.alias WHILE existingAlias#NIL DO IF from.name.Equal[existingAlias.name] THEN BEGIN IF from.depth < existingAlias.depth THEN existingAlias.depth _ from.depth; from _ from.alias; EXIT END REPEAT FINISHED => BEGIN <> tmp: REF SignalName = from; from _ from.alias; tmp.alias _ to.alias; to.alias _ tmp END ENDLOOP ENDLOOP END; -- MergeAliases fromSigProp: REF ANY ~ Properties.GetProp [properties, SXAtoms.SignalName]; exportProp: REF ANY = Properties.GetProp [properties, SXAtoms.export]; toSigProp: REF ANY ~ Properties.GetProp [node.properties, SXAtoms.SignalName]; <> IF SXAccess.sxTech.combineNodeProperties#NIL AND properties#NIL THEN node.properties _ SXAccess.sxTech.combineNodeProperties[circuit, node.properties, properties, qual]; <> BEGIN fromSignal: REF SignalName; toSignal: REF SignalName; depth: INTEGER _ 0; FOR q: LIST OF CD.Instance _ qual, q.rest WHILE q#NIL DO depth _ depth.SUCC ENDLOOP; fromSignal _ CopySignal [fromSigProp, depth]; IF fromSignal # NIL THEN fromSignal.makePort _ (fromSignal.makePort OR exportProp=$TRUE); toSignal _ NARROW[toSigProp]; IF (toSignal # NIL) AND (fromSignal # NIL) THEN BEGIN IF toSignal.depth > fromSignal.depth THEN BEGIN node.properties _ Properties.PutProp [node.properties, SXAtoms.SignalName, fromSignal]; MergeAliases [fromSignal, toSignal] END ELSE MergeAliases [toSignal, fromSignal] END ELSE IF (fromSignal # NIL) THEN node.properties _ Properties.PutProp[node.properties, SXAtoms.SignalName, fromSignal] END; <> node.properties _ Properties.PutProp [node.properties, UnMerged]; END; -- CopyNodeProperties AdjustNode: PUBLIC PROC [ node: REF SX.CircuitNode, layer: SpinifexLayerIndex, area: INT, perim: INT, mode: SX.AdjustmentMode _ relative] = BEGIN <> apRec: LIST OF AreaPerimRec _ node.dim; IF node.superceded # NIL THEN node _ LookupNode[node]; -- added Ch. J. Jan 30, 1985 WHILE apRec # NIL DO IF apRec.first.layer = layer THEN EXIT; apRec _ apRec.rest; REPEAT FINISHED => BEGIN node.dim _ CONS [AreaPerimRec [layer: layer, area: area, perim: perim], node.dim]; RETURN END ENDLOOP; SELECT mode FROM relative => BEGIN apRec.first.area _ apRec.first.area + area; apRec.first.perim _ apRec.first.perim + perim END; absolute => BEGIN apRec.first.area _ area; apRec.first.perim _ perim END; ENDCASE END; -- AdjustNode NormalizeCircuit: PUBLIC PROC [cir: REF Circuit] = BEGIN <> <> CompressCircuitNodeList: PROC = BEGIN mySpecialCN: REF SX.CircuitNode = NEW [SX.CircuitNode]; indirectList: LIST OF REF SX.CircuitNode ~ CONS [mySpecialCN, cir.nodes]; cn: LIST OF REF SX.CircuitNode; IF cir.nodes = NIL THEN RETURN; <> mySpecialCN.superceded _ NIL; mySpecialCN.properties _ NIL; cn _ indirectList; WHILE cn.rest # NIL DO node: REF SX.CircuitNode ~ cn.rest.first; IF (node.superceded # NIL) OR (CDProperties.GetListProp [propList: node.properties, prop: UnMerged] # NIL) THEN cn.rest _ cn.rest.rest ELSE cn _ cn.rest ENDLOOP; <> IF cir.nodes = NIL THEN ERROR; -- Impossible! We would have returned at start if NIL list, and at least some of the nodes must be non-superceded. cn _ indirectList; WHILE cn.rest # NIL DO IF cn.rest.first.superceded = mySpecialCN THEN cn.rest _ cn.rest.rest ELSE {cn _ cn.rest; cn.first.superceded _ mySpecialCN} ENDLOOP; cn _ cir.nodes _ indirectList.rest; WHILE cn # NIL DO cn.first.superceded _ NIL; cn _ cn.rest ENDLOOP; END; -- CompressCircuitNodeList CompressLinkages: PROC = BEGIN FOR linkages: LIST OF REF NodeLinkage _ cir.linkages, linkages.rest WHILE linkages#NIL DO FOR attached: LIST OF REF AttachedNode _ linkages.first.nodes, attached.rest WHILE attached#NIL DO IF attached.first.node#NIL THEN attached.first.node _ LookupNode[attached.first.node]; ENDLOOP ENDLOOP END; -- CompressLinkages CompressMergeDirectoryEntries: PROC = BEGIN IF cir.mergeDirectory # NIL THEN BEGIN dummy: SX.MergeRecList = CONS [[], NIL]; <> CountUnMerged: RefTab.EachPairAction = BEGIN IF CDProperties.GetListProp [NARROW[key, REF SX.CircuitNode].properties, UnMerged] # NIL THEN oldSize _ oldSize.PRED; RETURN [FALSE] END; -- CountUnMerged CompressMerge: RefTab.EachPairAction = BEGIN mergeList: SX.MergeRecList; IF CDProperties.GetListProp[NARROW[key, REF SX.CircuitNode].properties, UnMerged] = NIL THEN BEGIN dummy.rest _ NARROW [val]; mergeList _ dummy; WHILE mergeList.rest # NIL DO mergeList.rest.first.becomes _ LookupNode [mergeList.rest.first.becomes]; IF CDProperties.GetListProp [mergeList.rest.first.becomes.properties, UnMerged] # NIL THEN mergeList.rest _ mergeList.rest.rest ELSE mergeList _ mergeList.rest ENDLOOP; IF dummy.rest # NIL THEN IF NOT newTab.Insert [key, dummy.rest] THEN ERROR END; RETURN [FALSE] END; -- CompressMerge <
> <> oldSize: INT _ RefTab.GetSize [cir.mergeDirectory]; newTab: RefTab.Ref; [] _ RefTab.Pairs [cir.mergeDirectory, CountUnMerged]; IF oldSize <= 0 THEN {cir.mergeDirectory _ NIL; RETURN}; newTab _ RefTab.Create [((oldSize/3)*4)+1]; [] _ RefTab.Pairs [cir.mergeDirectory, CompressMerge]; cir.mergeDirectory _ newTab; IF (RefTab.GetSize [newTab] = 0) THEN cir.mergeDirectory _ NIL END -- if cir.mergeDirectory # NIL END; -- CompressMergeDirectoryEntries CompressBoxPaths: PROC [qt: REF SXQuadTree.QuadTree] = BEGIN FOR boxes: LIST OF REF SXQuadTree.Rectangle _ qt.boxes, boxes.rest WHILE boxes#NIL DO WITH boxes.first.nodeInformation SELECT FROM inst: CD.Instance => NULL; cn: REF SX.CircuitNode => boxes.first.nodeInformation _ LookupNode [cn]; cc: REF Constraint => NULL; ENDCASE => ERROR; ENDLOOP; FOR quad: SXQuadTree.AreaSplit IN SXQuadTree.AreaSplit DO IF qt.subTrees[quad] # NIL THEN CompressBoxPaths [qt.subTrees[quad]] ENDLOOP END; -- CompressBoxPaths <
> CompressCircuitNodeList []; CompressLinkages []; CompressMergeDirectoryEntries []; FOR layer: SpinifexLayerIndex IN [0..SXAccess.sxTech.numSpinifexLayers) DO IF (cir.spinifexLayers[layer].geometry # NIL) THEN CompressBoxPaths [cir.spinifexLayers[layer].geometry] ENDLOOP END; -- Normalise Circuit LookupNode: PUBLIC PROC [node: REF SX.CircuitNode] RETURNS [REF SX.CircuitNode] = BEGIN <> <> <> <> <> <<--Implements (partial) Galler-Fisher path compression.>> <> <<};>> IF node.superceded#NIL THEN { n1: REF SX.CircuitNode _ node; <<--find the actual node>> WHILE node.superceded#NIL DO node _ node.superceded ENDLOOP; <<--now node is the result>> <<--but as side effect, set all superceded fields to point to the result node>> WHILE n1.superceded#NIL DO n2: REF SX.CircuitNode _ n1.superceded; n1.superceded _ node; n1 _ n2; ENDLOOP; }; RETURN [node] END; -- LookupNode LookupMergeDirectory: PROC [ dir: RefTab.Ref, cn: REF SX.CircuitNode, qual: LIST OF CD.Instance] RETURNS [merge: SX.MergeRecList, newQual: LIST OF CD.Instance] = BEGIN found: BOOL; val: REF ANY; [found, val] _ RefTab.Fetch [dir, cn]; IF found THEN BEGIN <> FOR mergeList: SX.MergeRecList _ NARROW[val], mergeList.rest WHILE mergeList#NIL DO <> qApplChain: LIST OF CD.Instance _ qual; FOR applChain: LIST OF CD.Instance _ mergeList.first.applChain, applChain.rest DO IF applChain = NIL THEN RETURN [mergeList, qApplChain]; <> IF (qApplChain = NIL) OR (qApplChain.first # applChain.first) THEN EXIT; qApplChain _ qApplChain.rest ENDLOOP ENDLOOP END; -- found RETURN [NIL, qual] END; -- LookupMergeDirectory UnMerged: ATOM = $SXPrivateUnMerged; <> FindRootNode: PUBLIC PROC [ circuit: REF Circuit, subcircuitNode: REF SX.CircuitNode, qualifier: LIST OF CD.Instance, insertIfNotInCircuit: BOOL _ FALSE] RETURNS [node: REF SX.CircuitNode, rootQualifier: LIST OF CD.Instance] = BEGIN AddCircuitNodeMerge: PROC [sourceNode: REF SX.CircuitNode, qual: LIST OF CD.Instance] RETURNS [newNode: REF SX.CircuitNode] = BEGIN found: BOOL; mergeList: SX.MergeRecList _ NIL; IF circuit.mergeDirectory = NIL THEN BEGIN IF insertIfNotInCircuit THEN BEGIN <> circuit.mergeDirectory _ RefTab.Create [521]; -- A prime. found _ FALSE END END ELSE BEGIN -- circuit.mergeDirectory # NIL val: REF ANY; [found, val] _ RefTab.Fetch [circuit.mergeDirectory, sourceNode]; IF found THEN BEGIN mergeList _ NARROW [val]; <> FOR m: SX.MergeRecList _ mergeList, m.rest WHILE m#NIL DO q: LIST OF CD.Instance _ qual; FOR applChain: LIST OF CD.Instance _ m.first.applChain, applChain.rest DO IF (applChain = NIL) OR (q = NIL) THEN IF (applChain = NIL) AND (q = NIL) THEN RETURN [newNode _ m.first.becomes] ELSE EXIT ELSE IF (applChain.first # q.first) THEN EXIT; q _ q.rest ENDLOOP ENDLOOP END -- found END; -- circuit.mergeDirectory # NIL IF ~insertIfNotInCircuit THEN RETURN [newNode _ NIL]; newNode _ NEW [SX.CircuitNode _ [NIL, NIL, sourceNode.loc, NIL]]; FOR qa: LIST OF CD.Instance _ qual, qa.rest WHILE qa # NIL DO newNode.loc.xy _ CDBasics.MapPoint [pointInCell: newNode.loc.xy, cellInWorld: qa.first.trans] ENDLOOP; CopyNodeProperties [circuit, newNode, sourceNode.properties, qual]; newNode.properties _ Properties.PutProp [newNode.properties, UnMerged, UnMerged]; mergeList _ CONS [[applChain: qual, becomes: newNode], mergeList]; IF RefTab.Store[circuit.mergeDirectory, sourceNode, mergeList] = found THEN ERROR; AddCircuitNode [circuit, newNode] END; -- AddCircuitNodeMerge <> IF qualifier=NIL THEN RETURN [subcircuitNode, NIL]; <> FOR q: LIST OF CD.Instance _ qualifier.rest, q.rest WHILE q#NIL DO subcircuit: REF Circuit _ SXAccessInternal.GetLogicalCell[q.first.ob].circuit; IF subcircuit.mergeDirectory # NIL THEN BEGIN tmp: SX.MergeRecList; oldQual: LIST OF CD.Instance _ qualifier; [merge: tmp, newQual: qualifier] _ LookupMergeDirectory [subcircuit.mergeDirectory, subcircuitNode, qualifier]; IF tmp # NIL THEN BEGIN IF oldQual = NIL THEN ERROR; IF (qualifier # NIL) AND (qualifier.first.ob # q.first.ob) THEN ERROR; subcircuitNode _ tmp.first.becomes END END ENDLOOP; <> IF (node _ AddCircuitNodeMerge[sourceNode: subcircuitNode, qual: qualifier])=NIL THEN {node _ subcircuitNode; rootQualifier _ qualifier} ELSE rootQualifier _ NIL END; -- FindRootNode AddCircuitNode: PROC [cir: REF Circuit, cn: REF SX.CircuitNode] = INLINE BEGIN cir.nodes _ CONS[cn, cir.nodes] END; -- AddCircuitNode CreateLinkage: PUBLIC PROC [cir: REF Circuit, source: CD.Instance, length, width: CD.Number] RETURNS [REF NodeLinkage] = BEGIN cir.linkages _ CONS [NEW[NodeLinkage _ [source: source, l: length, w: width]], cir.linkages]; RETURN [cir.linkages.first]; END; -- CreateLinkage LinkageAttach: PUBLIC PROC [ link: REF NodeLinkage, attachType: ATOM, node: REF SX.CircuitNode _ NIL] = BEGIN link.nodes _ CONS [NEW [AttachedNode _ [attachType, node]], link.nodes] END; -- LinkageAttach MakeContextFilter: PROC [] = { sxContextFilter _ NEW[CD.ContextFilter_ALL[TRUE]]; sxContextFilter[CD.errorLayer] _ FALSE; sxContextFilter[CD.commentLayer] _ FALSE; sxContextFilter[CD.backgroundLayer] _ FALSE; sxContextFilter[CD.shadeLayer] _ FALSE; sxContextFilter[CD.selectionLayer] _ FALSE; }; MakeContextFilter[] END. <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<1st: Extensions to NormalizeCircuit to remove nodes which were inserted by FindRootNode but never actually merged into other nodes in this cell. This is done using a special property UnMerged which is attached to nodes created for subcell nodes and then deleted during merging by CopyNodeProperties. If node is never merged it still has UnMerged property during NormalizeCircuit, and should be removed from both node list and mergeDirectory.>> <<2nd: When first created mergeDirectory is made large (521 entries). During NormalizeCircuit it is remade with slightly more space than required number of entries. This is to improve performance on large designs.>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<>> <<>>