-- ChipExpandImpl.mesa -- A package to expand Chipmonk geometries for circuit -- extraction. -- last modified by E. McCreight, January 10, 1983 6:15 PM -- written by E. McCreight, December 11, 1981 11:46 AM DIRECTORY CellInstPQ, ChipDRC, ChipExpand, ChipFeature, ChipNetDefs, ChipOrient, ChipReticle, ChipWire, LeftFeaturePQ, MiscDefs, ppdddefs, ppdefs, RightFeaturePQ; ChipExpandImpl: PROGRAM IMPORTS CellInstPQ, ChipDRC, ChipExpand, ChipFeature, ChipNetDefs, ChipOrient, ChipReticle, MiscDefs, ppdddefs, ppdefs EXPORTS ChipNetDefs, ChipExpand, ppdefs SHARES ChipExpand = BEGIN OPEN ppdddefs, ppdefs, ChipNetDefs, ChipDRC, ChipExpand; aux: PUBLIC TYPE = CellProto; levIsConductor: ARRAY level OF BOOLEAN _ wireOK; joinTo: PUBLIC LONG POINTER TO netPtr _ NIL; xstrInst: PUBLIC XstrCallPtr _ NIL; ExtractorFeature: PUBLIC ExtractorFeatureProc; MakeInstance: PUBLIC PROCEDURE[item: ItemRef, slice: ChipWire.SlicePtr, futureFeatures: LeftFeaturePQ.LeftFeaturePQHandle, presentFeatures: RightFeaturePQ.RightFeaturePQHandle, cellQ, deadCellQ: CellInstPQ.CellInstPQHandle] = BEGIN OPEN ChipOrient; WITH caller: item.head SELECT FROM cell => BEGIN firstX1: Coord; itemCount: CARDINAL _ caller.proto.itemCount; FOR idx: CellIndex _ item.idx, idx+1 WHILE idx NIL, NOT levIsConductor[l] => NIL, net=NIL AND useText AND getTextProp[callLp]#NIL => (net _ NewQualifiedNet[f: f]), joinByMagic => (net _ JoinNet[net: net, f: f]), ENDCASE => NIL); IF joinTo#NIL THEN BEGIN f.net _ joinTo^ _ (IF f.net=NIL THEN JoinNet[net: joinTo^, f: f] ELSE MergeNets[n1: joinTo^, n2: f.net]); joinTo _ NIL; END; IF doingDRC AND f.net#NIL AND (joinByMagic -- a contact -- OR (SELECT f.lev FROM metal, metal2 => FALSE, ENDCASE => levIsConductor[l])) THEN GetNormalNetId[@f.net].couldBeLogo _ FALSE; END; IF ChipReticle.makingReticles THEN SELECT l FROM dif => BEGIN AddFeature[lev: nImplant, grow: implantBeyondThinOx]; AddFeature[lev: pWell, grow: wellBeyondDiffusion]; END; pdif => BEGIN AddFeature[lev: pImplant, grow: implantBeyondThinOx]; AddFeature[lev: nWell, grow: wellBeyondDiffusion]; END; pwelCont => BEGIN AddFeature[lev: pImplant, grow: implantBeyondThinOx]; AddFeature[lev: pWell, grow: wellBeyondDiffusion]; END; nwelCont => BEGIN AddFeature[lev: nImplant, grow: implantBeyondThinOx]; AddFeature[lev: nWell, grow: wellBeyondDiffusion]; END; ENDCASE => NULL ELSE IF doingDRC THEN SELECT l FROM nwel => AddFeature[lev: nPlusForbidden, grow: nWellToNPlus]; nwelCont => BEGIN AddFeature[lev: pPlusForbidden, grow: nPlusToPPlus]; AddFeature[lev: nWell, grow: wellBeyondDiffusion]; net _ WellNet[net: net, f: f]; AddFeature[lev: nPlusForbidden, grow: wellBeyondDiffusion+nWellToNPlus]; END; pwelCont => BEGIN AddFeature[lev: nPlusForbidden, grow: nPlusToPPlus]; AddFeature[lev: pWell, grow: wellBeyondDiffusion]; net _ WellNet[net: net, f: f]; AddFeature[lev: pPlusForbidden, grow: wellBeyondDiffusion+pWellToPPlus]; END; cut => IF cutPolyGapRequired THEN AddFeature[lev: polyForbidden, grow: cutPolyGap, net: net]; via => AddFeature[lev: cutForbidden, grow: viaCutGap, net: net]; ENDCASE => NULL; END; END; -- of NextFeature nullOutline: PROCEDURE[a,b,c,d: INTEGER, col: color, r: POINTER TO Rect] = {NULL}; nullText: PROCEDURE[a,b,c,d: INTEGER, s: STRING, r: POINTER TO Rect] = {NULL}; featureProcs: drRecord _ [ r: [x1: FIRST[locNum], x2: LAST[locNum], y1: FIRST[locNum], y2: LAST[locNum]], bigr: [x1: FIRST[locNum], x2: LAST[locNum], y1: FIRST[locNum], y2: LAST[locNum]], orArea: NextFeature, saveArea: NextFeature, outl: nullOutline, dtxt: nullText, minSize: 0]; net: CanonNetPtr _ NIL; ExtractorFeature.p _ ExtractorNextFeature; joinTo _ NIL; IF ChipReticle.makingReticles THEN callLp.ob.p.drawme[0] [ob: callLp.ob, x: 0, y: 0, pr: @featureProcs] ELSE p[ob: callLp.ob, x: 0, y: 0, pr: @featureProcs]; IF net#NIL THEN net _ DeRefNet[net]; END; -- of ExplodeFeatures callLp: listPtr _ ProtoSeq[@caller][idx]; nextItem: ItemRef _ [@caller, idx]; r: CoordRect _ ItemInWorld[nextItem]; SELECT TRUE FROM idx=item.idx => firstX1 _ r.x1; r.x1=firstX1 => NULL; ENDCASE => BEGIN -- re-insert remainder of caller CellInstPQ.InsertCellInstPQ[p: cellQ, item: [x: ItemInWorld[[@caller, idx]].x1, call: [@caller, idx]]]; EXIT; END; IF caller.caller.head#NIL OR callLp.selected OR ChipReticle.makingReticles THEN -- extract it! WITH ob: callLp.ob SELECT FROM cell => BEGIN inst: InstancePtr _ instanceZ.NEW[cell Instance _ [min: [x: r.x1, y: r.y1], orient: ComposeOrient[cellOrientInWorld: caller.orient, itemOrientInCell: callLp.idx], proto: MakeProto[@ob, caller.proto.locNumScale], caller: nextItem, sibling: caller.offspring, nets: cell[]]]; IF NOT ChipReticle.makingReticles THEN caller.offspring _ inst; [] _ ProtoSeq[inst]; -- make sure it's sorted in the -- orientation in which it's called CellInstPQ.InsertCellInstPQ[p: cellQ, item: [x: ItemInWorld[[inst, 0]].x1, call: [inst, 0]]]; CellInstPQ.InsertCellInstPQ[p: deadCellQ, item: [x: ItemInWorld[inst.caller].x2, call: [inst, 0]]]; END; xstr => BEGIN IF NOT ChipReticle.makingReticles THEN BEGIN -- put transistor instance in structure tree xstrInst _ instanceZ.NEW[xstr Instance _ [min: [x: r.x1, y: r.y1], orient: ComposeOrient[ cellOrientInWorld: caller.orient, itemOrientInCell: callLp.idx], proto: MakeProto[@ob, caller.proto.locNumScale], caller: nextItem, sibling: caller.offspring, nets: xstr[]]]; caller.offspring _ xstrInst; END; ExplodeFeatures[SELECT TRUE FROM ob.pullup => exPu0, ob.angle => exAXstr0, ENDCASE => exXstr0]; END; cont => ExplodeFeatures[ p: (SELECT ob.typ FROM butt => exBC0, burr => exBuC0, ENDCASE => ob.p.drawme[0]), joinByMagic: TRUE, useText: TRUE, cutPolyGapRequired: (SELECT ob.typ FROM mDif, mPDif, mmDif, mmPDif => TRUE, ENDCASE => FALSE)]; bus => ExplodeFeatures[p: ob.p.drawme[0]]; wire, rect => ExplodeFeatures[p: ob.p.drawme[0], useText: TRUE]; ENDCASE => NULL; ENDLOOP; -- on idx END; -- of cell ENDCASE; END; -- of MakeInstance ExitInstance: PUBLIC PROCEDURE[inst: InstancePtr] = BEGIN IF NOT ChipReticle.makingReticles THEN WITH dinst: inst SELECT FROM cell => IF ChipReticle.makingReticles THEN instanceZ.FREE[@inst] -- reticle making doesn't keep the structure tree ELSE CheckClusters[@dinst]; ENDCASE => NULL; END; -- of ExitCellCall NewQualifiedNet: PROCEDURE[f: FeaturePtr] RETURNS[CanonNetPtr] = BEGIN net: netPtr _ NewNet[2]; id: NormalNetIdPtr = GetNormalNetId[@net]; id.source _ NearestCellInstance[f.caller.head]; id.final _ [lev: f.lev, r: f.cover]; id.name _ qualified[see: f.caller.idx]; RETURN[CanonNet[net]]; END; JoinNet: PROCEDURE[net: NetPtr, f: FeaturePtr] RETURNS[cn: CanonNetPtr] = BEGIN IF net=NIL THEN BEGIN cn _ NewNet[2]; WITH did: cn.id SELECT FROM normal => did.source _ NearestCellInstance[f.caller.head]; ENDCASE => NULL; END ELSE cn _ RefCanonNet[net]; IF cn.id.final.r.x2 did.source _ NearestCellInstance[f.caller.head]; ENDCASE => NULL; END ELSE cn _ RefCanonNet[net]; wn _ (f.net _ NewNet[1]).id; wn.details _ well[attachedTo: cn]; wn.final _ [lev: f.lev, r: f.cover]; END; -- of WellNet NearestCellInstance: PUBLIC PROCEDURE[p: InstancePtr] RETURNS[CellCallPtr] = BEGIN WHILE p#NIL DO WITH dp: p SELECT FROM cell => RETURN[@dp]; ENDCASE => p _ dp.caller.head; ENDLOOP; RETURN[NIL]; END; CheckClusters: PUBLIC PROCEDURE[call: CellCallPtr] = BEGIN callX2: Coord _ (IF call.caller.head#NIL THEN ItemInWorld[call.caller].x2 ELSE LAST[Coord]); FOR cluster: ClusterPtr _ call.clusters, cluster.next WHILE cluster#NIL DO CheckCluster[call, callX2, @cluster.first]; ENDLOOP; END; -- of CheckClusters CheckCluster: PROCEDURE[call: CellCallPtr, callX2: Coord, cluster: MustConnectPtr] = BEGIN mustConnect, nextMustConnect: MustConnectPtr; PreviousNet: PROCEDURE[net: netPtr] RETURNS[BOOLEAN] = BEGIN FOR mcp: MustConnectPtr _ cluster, mcp.next WHILE mcp#NIL DO IF net=mcp.net THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; END; IF cluster.next=NIL THEN RETURN; -- singleton -- First, try to locate a still-active net for the -- cluster head. FOR mustConnect _ cluster, mustConnect.next WHILE mustConnect#NIL DO IF callX2<= (mustConnect.net _ CanonNet[mustConnect.net]).id.final.r.x2 THEN BEGIN copyCluster: MustConnect _ cluster^; copyMustConnect: MustConnect _ mustConnect^; copyCluster.next _ mustConnect.next; copyMustConnect.next _ cluster.next; cluster^ _ copyMustConnect; mustConnect^ _ copyCluster; EXIT; END; ENDLOOP; nextMustConnect _ cluster.next; cluster.next _ NIL; FOR mustConnect _ nextMustConnect, nextMustConnect WHILE mustConnect#NIL DO mustConnectNet: CanonNetPtr _ mustConnect.net _ CanonNet[mustConnect.net]; nextMustConnect _ mustConnect.next; SELECT TRUE FROM PreviousNet[mustConnectNet] => FreeMustConnect[call, mustConnect]; -- same as some previous constraint ENDCASE => BEGIN mustConnect.next _ cluster.next; cluster.next _ mustConnect; END; ENDLOOP; END; -- of CheckCluster FreeMustConnect: PROCEDURE[call: CellCallPtr, mustConnect: MustConnectPtr] = BEGIN mustConnect.net _ DeRefNet[mustConnect.net]; clusterZ.FREE[@mustConnect]; END; -- of FreeMustConnect ProtoSeq: PUBLIC PROCEDURE[inst: InstancePtr] RETURNS[ListPtrSeqPtr] = BEGIN sortClass: SortClass _ orientToSortClass[inst.orient]; proto: ProtoPtr _ inst.proto; IF proto.seq[sortClass]=NIL THEN BEGIN i: CellIndex _ 0; lps: ListPtrSeqPtr _ uz.NEW[ListPtrSeq[proto.itemCount]]; FOR lpp: listPtr _ proto.lp, lpp.nxt WHILE lpp#NIL DO lps[i] _ lpp; i _ i+1; ENDLOOP; SortListPtrSeq[lps, SortOrder[sortClass]]; proto.seq[sortClass] _ lps; END; RETURN[proto.seq[sortClass]]; END; MakeProto: PUBLIC PROCEDURE[ob: obPtr, locNumScale: LocNumScale _ lambdaRelative, name: STRING _ NIL] RETURNS[c: ProtoPtr] = BEGIN IF ob.auxPnt=NIL THEN BEGIN -- We'll have to make one up. scale: Coord _ coordScale[locNumScale]; cp: ProtoPtr _ ob.auxPnt _ uz.NEW[CellProto _ [ob: ob, locNumScale: locNumScale, stretchMasks: locNumScale=lambdaRelative, size: [x: scale*ob.size[0], y: scale*ob.size[1]]]]; count: CARDINAL _ 0; WITH o: ob SELECT FROM cell => BEGIN FOR lp: listPtr _ o.ptr, lp.nxt WHILE lp#NIL DO count _ count+1 ENDLOOP; cp.lp _ o.ptr; END; xstr => cp.lp _ NIL; ENDCASE => MiscDefs.CallDebugger["Can't expand this ob type"]; cp.itemCount _ count; IF name#NIL THEN cp.name _ name ELSE FOR cl: LONG POINTER TO cList _ cellList, cl.nxt WHILE cl#NIL DO IF cl.ob=ob THEN {cp.name _ cl.name; EXIT}; ENDLOOP; END; RETURN[ob.auxPnt]; END; -- of MakeProto origCifScale: PUBLIC INTEGER; -- centiMicrometers per lambda lambdaRelativeCoordScale: PUBLIC Coord; -- Coords per ppdefs.locNum coordScale: PUBLIC ARRAY LocNumScale OF Coord; SetCoordScale: PROCEDURE[] = BEGIN -- from Chipmonk feedback window origCifScale _ ppdddefs.pCifScale; -- centiMicrometers per lambda lambdaRelativeCoordScale _ -- to Coords = nanometers (origCifScale*10)/Lambda; coordScale _ -- to nanometers [ lambdaRelative: lambdaRelativeCoordScale, absolute: 250 -- looks like 0.5 um lambda -- this may be overwritten later ]; END; -- of SetCoordScale NullLpAux: PROCEDURE[lp: listPtr] = BEGIN WHILE lp#NIL DO NullObAux[lp.ob]; lp _ lp.nxt; ENDLOOP; END; NullObAux: PROCEDURE[ob: obPtr] = BEGIN ob.auxPnt _ NIL; WITH o: ob SELECT FROM cell => NullLpAux[o.ptr]; ENDCASE => NULL; END; -- Module START code implantBeyondThinOx, wellBeyondDiffusion, cutPolyGap, nPlusToPPlus, nWellToNPlus, pWellToPPlus, viaCutGap: Coord; NullLpAux[masterList]; SetCoordScale[]; implantBeyondThinOx _ ScaleFromChipmonk[(3*Lambda)/2]; wellBeyondDiffusion _ ScaleFromChipmonk[3*Lambda]; cutPolyGap _ ScaleFromChipmonk[2*Lambda]; viaCutGap _ ScaleFromChipmonk[3*Lambda]; nPlusToPPlus _ ScaleFromChipmonk[3*Lambda]; nWellToNPlus _ ScaleFromChipmonk[3*Lambda]; pWellToPPlus _ ScaleFromChipmonk[3*Lambda]; END. -- of ChipExpandImpl