-- 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<itemCount DO ExplodeFeatures: PROCEDURE[p: drProc, joinByMagic: BOOLEAN ← FALSE, useText: BOOLEAN ← TRUE, cutPolyGapRequired: BOOLEAN ← FALSE] = BEGIN ExtractorNextFeature: PROCEDURE[ x1, y1, x2, y2: locNum, lev: ExtractLevel] = BEGIN IF x1<=x2 AND y1<=y2 THEN BEGIN innerR: Rect ← ChipOrient.MapRect[ itemInCell: [x1: x1, y1: y1, x2: x2, y2: y2], cellInstOrient: callLp.idx, cellSize: [x: callLp.ob.size[0], y: callLp.ob.size[1]], cellInstPos: [x: callLp.lx, y: callLp.ly] ]; ob: obPtr ← caller.proto.ob; r: Rect ← ChipOrient.MapRect[ itemInCell: innerR, cellInstOrient: caller.orient, cellSize: [x: ob.size[0], y: ob.size[1]]]; min: CoordPoint ← caller.min; scale: Coord ← coordScale[caller.proto.locNumScale]; cr: CoordRect ← [ x1: min.x+scale*r.x1, y1: min.y+scale*r.y1, x2: min.x+scale*r.x2, y2: min.y+scale*r.y2]; [] ← ChipFeature.NewFeature[cover: cr, lev: lev, caller: nextItem, lq: futureFeatures]; END; END; -- of ExtractorNextFeature NextFeature: PROCEDURE[x1, y1, x2, y2: locNum, l: level, p: POINTER TO Rect] = BEGIN IF x1<=x2 AND y1<=y2 THEN BEGIN AddFeature: PROCEDURE[lev: ExtractLevel, grow: Coord ← 0, net: netPtr ← NIL] = BEGIN f ← ChipFeature.NewFeature[ cover: [x1: cr.x1-grow, y1: cr.y1-grow, x2: cr.x2+grow, y2: cr.y2+grow], lev: lev, caller: nextItem, lq: futureFeatures]; IF net#NIL THEN f.net ← RefCanonNet[net]; END; f: FeaturePtr; innerR: Rect ← ChipOrient.MapRect[ itemInCell: [x1: x1, y1: y1, x2: x2, y2: y2], cellInstOrient: callLp.idx, cellSize: [x: callLp.ob.size[0], y: callLp.ob.size[1]], cellInstPos: [x: callLp.lx, y: callLp.ly] ]; ob: obPtr ← caller.proto.ob; r: Rect ← ChipOrient.MapRect[ itemInCell: innerR, cellInstOrient: caller.orient, cellSize: [x: ob.size[0], y: ob.size[1]]]; min: CoordPoint ← caller.min; scale: Coord ← coordScale[caller.proto.locNumScale]; cr: CoordRect ← [ x1: min.x+scale*r.x1, y1: min.y+scale*r.y1, x2: min.x+scale*r.x2, y2: min.y+scale*r.y2]; IF l#unknown THEN BEGIN f ← ChipFeature.NewFeature[cover: cr, lev: l, caller: nextItem, lq: futureFeatures]; f.net ← (SELECT TRUE FROM ChipReticle.makingReticles => 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<f.cover.x2 THEN cn.id.final ← [lev: f.lev, r: f.cover]; END; -- of JoinNet WellNet: PROCEDURE[net: NetPtr, f: FeaturePtr] RETURNS[cn: CanonNetPtr] = BEGIN wn: NetIdPtr; 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]; 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