<> <> <> <> DIRECTORY CD, CDCallSpecific, CDCommandOps, CDBasics, CDIO, CDLRUCache, CDOrient, CDStretchyExtras, CDValue, NMos, NMosTransistors, Rope, TokenIO; NMosTransistorsImpl: CEDAR PROGRAM IMPORTS CDCallSpecific, CDCommandOps, CDBasics, CDIO, CDLRUCache, CDOrient, CDStretchyExtras, CDValue, NMos, Rope, TokenIO EXPORTS NMosTransistors = BEGIN OPEN NMos; lambda: CD.Number = NMos.lambda; depletionOverlap: CD.Number = (3*lambda)/2; wXExtension: CD.Number = NMosTransistors.wXExtension; lXExtension: CD.Number = NMosTransistors.lXExtension; TransistorPtr: TYPE = NMosTransistors.TransistorPtr; TransistorRec: TYPE = NMosTransistors.TransistorRec; tCache: CDLRUCache.LRUCache = CDLRUCache.Create[size: 10, aequivalenceProc: Aequivalent, newProc: NewTrans]; aCache: CDLRUCache.LRUCache = CDLRUCache.Create[size: 10, aequivalenceProc: Aequivalent, newProc: NewTrans]; pCache: CDLRUCache.LRUCache = CDLRUCache.Create[size: 10, aequivalenceProc: Aequivalent, newProc: NewTrans]; Aequivalent: PROC[mySpecific, other: REF ANY] RETURNS [BOOL] = { WITH other SELECT FROM tp2: TransistorPtr => RETURN [NARROW[mySpecific, TransistorPtr]^=tp2^]; ENDCASE => RETURN [FALSE] }; NewTrans: PROC [] RETURNS [CD.Object] = { ob: CD.Object ~ NEW[CD.ObjectRep]; ob.specificRef _ NEW[TransistorRec]; RETURN [ob] }; Init: PROC [] = BEGIN pForTransistors.drawMe _ pForTransistors.quickDrawMe _ DrawMeForTransistors; pForTransistors.internalRead _ ReadTrans; pForTransistors.internalWrite _ WriteTrans; pForTransistors.describe _ Describe; CDStretchyExtras.InstallMatch[pForTransistors, MatchTrans]; CDCallSpecific.Register[$ChangeExt, pForTransistors, ChangeExtensionTrans]; CDCallSpecific.Register[$Lengthen, pForTransistors, LengthenTrans]; CDCallSpecific.Register[$Default, pForTransistors, DefaultenTrans]; CDCallSpecific.Register[$SetLength, pForTransistors, SetLengthTrans]; CDCallSpecific.Register[$SetWidth, pForTransistors, SetWidthTrans]; pForATransistors.drawMe _ pForATransistors.quickDrawMe _ DrawMeForATransistors; pForATransistors.internalRead _ ReadATrans; pForATransistors.internalWrite _ WriteATrans; pForPullUps.drawMe _ pForPullUps.quickDrawMe _ DrawMeForPullUps; pForPullUps.internalRead _ ReadPull; pForPullUps.internalWrite _ WritePull; pForPullUps.describe _ Describe; CDStretchyExtras.InstallMatch[pForPullUps, MatchTrans]; CDCallSpecific.Register[$ChangeExt, pForPullUps, ChangeExtensionPullUps]; CDCallSpecific.Register[$Lengthen, pForPullUps, LengthenPullUps]; CDCallSpecific.Register[$Default, pForPullUps, DefaultenPullUps]; CDCallSpecific.Register[$SetLength, pForPullUps, SetLengthPullUps]; CDCallSpecific.Register[$SetWidth, pForPullUps, SetWidthPullUps]; END; Describe: PROC[me: CD.Object] RETURNS [Rope.ROPE] = BEGIN tp: TransistorPtr = NARROW[me.specificRef]; r: Rope.ROPE; IF tp.pullup THEN r _ "pullup " ELSE { r _ "transistor "; IF tp.angle THEN r _ Rope.Concat["angle ", r]; r _ Rope.Concat[r, SELECT tp.implant FROM NMosTransistors.enhancement => "enh ", NMosTransistors.zeroTresh => "0-tresh ", NMosTransistors.weakDepletion => "wk depl ", NMosTransistors.strongDepletion => "depl ", ENDCASE => "ERROR" ] }; r _ Rope.Cat[ r, " [", CDCommandOps.LambdaRope[tp.width], CDCommandOps.LambdaRope[tp.length], "]" ]; RETURN [r] END; MatchTrans: PROC [me: CD.Object, r: CD.Rect, layer: CD.Layer, prim: BOOL, horz: BOOL] RETURNS [BOOL] = BEGIN RETURN [layer=NMos.pol OR layer=me.layer] END; <<-- Transistor -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- >> pForTransistors: CD.ObjectClass = RegisterObjectClass[$NMosTransistor]; CreateTransistor: PUBLIC PROC [w, l: CD.Number, implant: NMosTransistors.Implant_NMosTransistors.enhancement, wExt: CD.Number_wXExtension, lExt: CD.Number_lXExtension] RETURNS [CD.Object] = BEGIN tob: CD.Object ~ tCache.UnusedOrNew[]; tp: TransistorPtr ~ NARROW[tob.specificRef]; tob.class _ pForTransistors; w _ MAX[w, 2*lambda]; l _ MAX[l, 2*lambda]; wExt _ MAX[wExt, 0]; lExt _ MAX[lExt, 0]; tp.width _ w; tp.length _ l; tp.wExt _ wExt; tp.lExt _ lExt; tob.size _ [w+2*wExt, l+2*lExt]; tp.implant _ implant; tp.angle _ FALSE; tp.pullup _ FALSE; tob.layer _ dif; RETURN [tCache.ReplaceByAequivalent[tob]] END; ReadTrans: CD.InternalReadProc --PROC [] RETURNS [Object]-- = BEGIN w: INT = TokenIO.ReadInt[]; l: INT = TokenIO.ReadInt[]; implant: INT = TokenIO.ReadInt[]; wExt: INT = TokenIO.ReadInt[]; lExt: INT = TokenIO.ReadInt[]; IF CDIO.VersionKey[]>=2 THEN RETURN [CreateTransistor[w: w, l: l, implant: implant, wExt: wExt, lExt: lExt]] ELSE RETURN [CreateTransistor[w: w, l: l, implant: (IF implant=1 THEN 3 ELSE 0), wExt: wExt, lExt: lExt]]; END; WriteTrans: CD.InternalWriteProc -- PROC [me: Object] -- = BEGIN tp: TransistorPtr = NARROW[me.specificRef]; TokenIO.WriteInt[tp.width]; TokenIO.WriteInt[tp.length]; TokenIO.WriteInt[tp.implant]; TokenIO.WriteInt[tp.wExt]; TokenIO.WriteInt[tp.lExt]; END; ToPosition: PROC [x: REF] RETURNS [class: CD.Position] = <<--y field defaults to lambda, x field defaults to 0>> <<--[0, 0] if not done>> BEGIN IF x=NIL THEN class _ [0, lambda] ELSE WITH x SELECT FROM rp: REF CD.Position => class _ rp^; rn: REF CD.Number => class _ [0, rn^]; ENDCASE => class _ [0, 0]; END; AngleExt: PROC[tob: CD.Object] RETURNS [CD.Number] = { tp: TransistorPtr = NARROW[tob.specificRef]; RETURN [tp.width+tp.length+tp.wExt-tob.size.x] }; ChangeExtensionTrans: CDCallSpecific.CallProc = BEGIN amount: CD.Position = ToPosition[x]; IF amount=[0, 0] THEN done _ FALSE ELSE { tp: TransistorPtr _ NARROW[inst.ob.specificRef]; ap: CD.Instance _ NEW[CD.InstanceRep_inst^]; sz: CD.Position _ CDBasics.AddPoints[[x: tp.wExt, y: tp.lExt], amount]; IF sz.x<0 OR sz.y<0 THEN {done_FALSE; RETURN}; IF tp.angle THEN ap.ob _ CreateAngleTransistor[w: tp.width, l: tp.length, implant: tp.implant, wExt: sz.x, lExt: sz.y, aExt: AngleExt[inst.ob] ] ELSE ap.ob _ CreateTransistor[w: tp.width, l: tp.length, implant: tp.implant, wExt: sz.x, lExt: sz.y ]; include _ LIST[ap]; removeMe _ TRUE; repaintMe _ amount.x<0 OR amount.y<0; repaintInclude _ amount.x>0 OR amount.y>0; } END; LengthenTrans: CDCallSpecific.CallProc = BEGIN tp: TransistorPtr = NARROW[inst.ob.specificRef]; new: CD.Object; amount, sz: CD.Position; IF x=NIL THEN amount _ [0, lambda] ELSE IF ISTYPE [x, REF CD.Position] THEN amount _ NARROW[x, REF CD.Position]^ ELSE {done_FALSE; RETURN}; sz _ CDBasics.AddPoints[[x: tp.width, y: tp.length], amount]; IF sz.x<=0 OR sz.y<=0 THEN {done _ FALSE; RETURN}; IF tp.angle THEN new _ CreateAngleTransistor[w: sz.x, l: sz.y, wExt: tp.wExt, lExt: tp.lExt, implant: tp.implant, aExt: AngleExt[inst.ob] ] ELSE new _ CreateTransistor[w: sz.x, l: sz.y, wExt: tp.wExt, lExt: tp.lExt, implant: tp.implant ]; IF new#NIL AND (inst.ob.size#new.size OR NOT Aequivalent[tp, new.specificRef]) THEN inst.ob _ new ELSE done _ FALSE; repaintMe _ done; END; DefaultenTrans: CDCallSpecific.CallProc = BEGIN tp: TransistorPtr _ NARROW[inst.ob.specificRef]; ap: CD.Instance _ NEW[CD.InstanceRep_inst^]; ap.ob _ CreateTransistor[ w: CDValue.FetchInt[design, $NMosTransistorW]*lambda, l: CDValue.FetchInt[design, $NMosTransistorH]*lambda, wExt: tp.wExt, lExt: tp.lExt, implant: CDValue.FetchInt[design, $NMosTransistorImplant] ]; include _ LIST[ap]; removeMe _ TRUE; repaintMe _ TRUE; repaintInclude _ TRUE; END; SetWidthTrans: CDCallSpecific.CallProc = BEGIN tp: TransistorPtr _ NARROW[inst.ob.specificRef]; newWidth: CD.Number _ NARROW[x, REF CD.Number]^; oldWidth: CD.Number _ tp.width; ap: CD.Instance _ NEW[CD.InstanceRep_inst^]; ap.ob _ CreateTransistor[w: newWidth, l: tp.length, wExt: tp.wExt, lExt: tp.lExt, implant: tp.implant]; include _ LIST[ap]; removeMe _ TRUE; IF newWidth>oldWidth THEN repaintInclude _ TRUE ELSE repaintMe _ TRUE; END; SetLengthTrans: CDCallSpecific.CallProc = BEGIN tp: TransistorPtr _ NARROW[inst.ob.specificRef]; newLength: CD.Number _ NARROW[x, REF CD.Number]^; oldLength: CD.Number _ tp.length; ap: CD.Instance _ NEW[CD.InstanceRep_inst^]; ap.ob _ CreateTransistor[w: tp.width, l: newLength, wExt: tp.wExt, lExt: tp.lExt, implant: tp.implant]; include _ LIST[ap]; removeMe _ TRUE; IF newLength>oldLength THEN repaintInclude_TRUE ELSE repaintMe_TRUE; END; DrawMeForTransistors: PROC [inst: CD.Instance, pos: CD.Position, orient: CD.Orientation, pr: CD.DrawRef] = BEGIN class: TransistorPtr = NARROW[inst.ob.specificRef]; CDDraw: PROC[r: CD.Rect, l: CD.Layer] = INLINE <> BEGIN pr.drawRect[ CDOrient.MapRect[ itemInCell: r, cellSize: inst.ob.size, cellInstOrient: orient, cellInstPos: pos], l, pr]; END; CDDraw[[class.wExt, 0, class.wExt+class.width, inst.ob.size.y], inst.ob.layer]; -- dif or pdiff CDDraw[[0, class.lExt, inst.ob.size.x, class.lExt+class.length], pol]; IF class.implant>0 THEN CDDraw[[class.wExt-depletionOverlap, class.lExt-depletionOverlap, inst.ob.size.x-class.wExt+depletionOverlap, inst.ob.size.y-class.lExt+depletionOverlap], SELECT class.implant FROM NMosTransistors.strongDepletion => imp, NMosTransistors.weakDepletion => impWeak, NMosTransistors.zeroTresh => imp0, NMosTransistors.enhancement => CD.errorLayer, ENDCASE => CD.errorLayer ]; END; <<-- Angle Transistor -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- >> pForATransistors: CD.ObjectClass = RegisterObjectClass[$NMosATransistor]; CreateAngleTransistor: PUBLIC PROC [w, l: CD.Number, implant: NMosTransistors.Implant_NMosTransistors.enhancement, wExt: CD.Number_wXExtension, lExt: CD.Number_lXExtension, aExt: CD.Number_0] RETURNS [CD.Object] = BEGIN tob: CD.Object _ aCache.UnusedOrNew[]; tp: TransistorPtr _ NARROW[tob.specificRef]; tob.class _ pForATransistors; wExt _ MAX[wExt, 0]; lExt _ MAX[lExt, 0]; aExt _ MAX[aExt, -lExt]; w _ MAX[w, 2*lExt]; -- the width of the straight-line <<-- parts of the gate, excluding corner>> l _ MAX[l, 2*lambda]; tp.width _ w; tp.length _ l; tp.wExt _ wExt; tp.lExt _ lExt; tob.size _ [w+l+wExt-aExt, wExt+2*lExt+aExt+l]; tp.implant _ implant; tp.angle _ TRUE; tp.pullup _ FALSE; tob.layer _ dif; RETURN [aCache.ReplaceByAequivalent[tob]] END; ReadATrans: CD.InternalReadProc --PROC [] RETURNS [Object]-- = BEGIN w: INT = TokenIO.ReadInt[]; l: INT = TokenIO.ReadInt[]; implant: INT = TokenIO.ReadInt[]; wExt: INT = TokenIO.ReadInt[]; lExt: INT = TokenIO.ReadInt[]; aExt: INT = TokenIO.ReadInt[]; IF CDIO.VersionKey[]>=2 THEN RETURN [ CreateAngleTransistor[w: w, l: l, implant: implant, wExt: wExt, lExt: lExt, aExt: aExt] ] ELSE RETURN [ CreateAngleTransistor[w: w, l: l, implant: (IF implant=1 THEN 3 ELSE 0), wExt: wExt, lExt: lExt, aExt: aExt] ]; END; WriteATrans: CD.InternalWriteProc -- PROC [me: Object] -- = BEGIN tp: TransistorPtr = NARROW[me.specificRef]; TokenIO.WriteInt[tp.width]; TokenIO.WriteInt[tp.length]; TokenIO.WriteInt[tp.implant]; TokenIO.WriteInt[tp.wExt]; TokenIO.WriteInt[tp.lExt]; TokenIO.WriteInt[tp.width+tp.length+tp.wExt-me.size.x]; END; DrawMeForATransistors: PROC [inst: CD.Instance, pos: CD.Position, orient: CD.Orientation, pr: CD.DrawRef] = BEGIN class: TransistorPtr = NARROW[inst.ob.specificRef]; CDDraw: PROC[r: CD.Rect, l: CD.Layer] = INLINE <<--uses outer stuff!!>> BEGIN pr.drawRect[ CDOrient.MapRect[ itemInCell: r, cellSize: inst.ob.size, cellInstOrient: orient, cellInstPos: pos], l, pr]; END; <<--The transistor makes a 90-degree bend, going eastward and>> <<--then southward. The diffusion on the outer side of the angle,>> <<--that is, on the northeast side, is arbitrarily called the drain.>> IF CDBasics.Intersect[CDOrient.RectAt[pos, inst.ob.size, orient], pr.interestClip] THEN BEGIN ele: CD.Number = 2*class.lExt+class.length; hPoly: CD.Rect = [0, class.lExt, inst.ob.size.x-class.lExt, class.length+class.lExt]; -- horizontal vPoly: CD.Rect = [inst.ob.size.x-class.length-class.lExt, hPoly.y2, hPoly.x2, inst.ob.size.y]; -- vertical nDrain: CD.Rect = [class.wExt, 0, inst.ob.size.x, hPoly.y1]; -- north eDrain: CD.Rect = [vPoly.x2, nDrain.y2, nDrain.x2, inst.ob.size.y-class.wExt]; -- east wSource: CD.Rect = [inst.ob.size.x-ele, eDrain.y1, eDrain.x1, inst.ob.size.y-class.wExt]; -- west sSource: CD.Rect = [MIN[class.wExt, wSource.x1], nDrain.y2, wSource.x1, MIN[ele, wSource.y2]]; -- south IF class.lExt>0 THEN BEGIN CDDraw[nDrain, inst.ob.layer]; CDDraw[eDrain, inst.ob.layer]; END; CDDraw[wSource, inst.ob.layer]; CDDraw[sSource, inst.ob.layer]; CDDraw[hPoly, pol]; CDDraw[vPoly, pol]; IF class.implant>0 THEN BEGIN CDDraw[[nDrain.x1-depletionOverlap, hPoly.y1-depletionOverlap, hPoly.x2+depletionOverlap, hPoly.y2+depletionOverlap], imp]; CDDraw[[vPoly.x1-depletionOverlap, vPoly.y1-depletionOverlap, vPoly.x2+depletionOverlap, eDrain.y2+depletionOverlap], imp]; END END END; <<-- PullUp -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- >> pForPullUps: CD.ObjectClass = RegisterObjectClass[$NMosPullUp]; CreatePullUp: PUBLIC PROC [w, l: CD.Number, wExt: CD.Number_wXExtension, lExt: CD.Number_lXExtension] RETURNS [CD.Object] = BEGIN puob: CD.Object ~ pCache.UnusedOrNew[]; pup: TransistorPtr ~ NARROW[puob.specificRef]; w _ MAX[w, 2*lambda]; l _ MAX[l, 2*lambda]; wExt _ MAX[wExt, 0]; lExt _ MAX[lExt, 0]; pup.wExt _ wExt; pup.lExt _ lExt; pup.width _ w; pup.length _ l; pup.pullup _ TRUE; puob.class _ pForPullUps; puob.size _ [MAX[4*lambda, w+wExt*2], MAX[6*lambda, l+lExt+3*lambda]]; puob.layer _ dif; RETURN [pCache.ReplaceByAequivalent[puob]] END; ReadPull: CD.InternalReadProc --PROC [] RETURNS [Object]-- = BEGIN w: INT = TokenIO.ReadInt[]; l: INT = TokenIO.ReadInt[]; wExt: INT = TokenIO.ReadInt[]; lExt: INT = TokenIO.ReadInt[]; RETURN [ CreatePullUp[w: w, l: l, wExt: wExt, lExt: lExt] ]; END; WritePull: CD.InternalWriteProc -- PROC [me: Object] -- = BEGIN tp: TransistorPtr = NARROW[me.specificRef]; TokenIO.WriteInt[tp.width]; TokenIO.WriteInt[tp.length]; TokenIO.WriteInt[tp.wExt]; TokenIO.WriteInt[tp.lExt]; END; LengthenPullUps: CDCallSpecific.CallProc = BEGIN amount: CD.Position = ToPosition[x]; IF amount=[0, 0] THEN done _ FALSE ELSE { tp: TransistorPtr = NARROW[inst.ob.specificRef]; ap: CD.Instance = NEW[CD.InstanceRep_inst^]; sz: CD.Position = CDBasics.AddPoints[[x: tp.width, y: tp.length], amount]; IF sz.x<=0 OR sz.y<=0 THEN {done_FALSE; RETURN}; ap.ob _ CreatePullUp[w: sz.x, l: sz.y, wExt: tp.wExt, lExt: tp.lExt]; include _ LIST[ap]; removeMe _ TRUE; repaintMe _ amount.x<0 OR amount.y<0; repaintInclude _ amount.x>0 OR amount.y>0; } END; ChangeExtensionPullUps: CDCallSpecific.CallProc = BEGIN amount: CD.Position = ToPosition[x]; IF amount=[0, 0] THEN done _ FALSE ELSE { tp: TransistorPtr = NARROW[inst.ob.specificRef]; ap: CD.Instance = NEW[CD.InstanceRep_inst^]; sz: CD.Position _ CDBasics.AddPoints[[x: tp.wExt, y: tp.lExt], amount]; IF sz.x<0 OR sz.y<0 THEN {done_FALSE; RETURN}; ap.ob _ CreatePullUp[w: tp.width, l: tp.length, wExt: sz.x, lExt: sz.y]; include _ LIST[ap]; removeMe _ TRUE; repaintMe _ amount.x<0 OR amount.y<0; repaintInclude _ amount.x>0 OR amount.y>0; } END; DefaultenPullUps: CDCallSpecific.CallProc = BEGIN tp: TransistorPtr = NARROW[inst.ob.specificRef]; ap: CD.Instance = NEW[CD.InstanceRep_inst^]; ap.ob _ CreatePullUp[ w: CDValue.FetchInt[design, $NMosPullUpW]*lambda, l: CDValue.FetchInt[design, $NMosPullUpH]*lambda, wExt: tp.wExt, lExt: tp.lExt]; include _ LIST[ap]; removeMe _ TRUE; repaintMe _ TRUE; repaintInclude _ TRUE; END; SetWidthPullUps: CDCallSpecific.CallProc = BEGIN tp: TransistorPtr _ NARROW[inst.ob.specificRef]; newWidth: CD.Number _ NARROW[x, REF CD.Number]^; oldWidth: CD.Number _ tp.width; ap: CD.Instance _ NEW[CD.InstanceRep_inst^]; ap.ob _ CreatePullUp[w: newWidth, l: tp.length, wExt: tp.wExt, lExt: tp.lExt]; include _ LIST[ap]; removeMe _ TRUE; IF newWidth>oldWidth THEN repaintInclude _ TRUE ELSE repaintMe _ TRUE; END; SetLengthPullUps: CDCallSpecific.CallProc = BEGIN tp: TransistorPtr _ NARROW[inst.ob.specificRef]; newLength: CD.Number _ NARROW[x, REF CD.Number]^; oldLength: CD.Number _ tp.length; ap: CD.Instance _ NEW[CD.InstanceRep_inst^]; ap.ob _ CreatePullUp[w: tp.width, l: newLength, wExt: tp.wExt, lExt: tp.lExt]; include _ LIST[ap]; removeMe _ TRUE; IF newLength>oldLength THEN repaintInclude _ TRUE ELSE repaintMe _ TRUE; END; DrawMeForPullUps: PROC [inst: CD.Instance, pos: CD.Position, orient: CD.Orientation, pr: CD.DrawRef] = BEGIN CDDraw: PROC[r: CD.Rect, l: CD.Layer] = INLINE <<--uses outer stuff!!>> BEGIN pr.drawRect[ CDOrient.MapRect[ itemInCell: r, cellSize: inst.ob.size, cellInstOrient: orient, cellInstPos: pos], l, pr]; END; IF CDBasics.Intersect[CDOrient.RectAt[pos, inst.ob.size, orient], pr.interestClip] THEN BEGIN class: TransistorPtr = NARROW[inst.ob.specificRef]; middleX: CD.Number = inst.ob.size.x/2; metal: CD.Rect = [x1: middleX-2*lambda, y1: inst.ob.size.y-6*lambda, x2: middleX+2*lambda, y2: inst.ob.size.y]; CDDraw[[class.wExt, 0, class.wExt+class.width, inst.ob.size.y], inst.ob.layer]; CDDraw[[0, class.lExt, inst.ob.size.x, class.lExt+class.length], pol]; CDDraw[[0, 0, inst.ob.size.x, inst.ob.size.y-lambda], imp]; CDDraw[[metal.x1, metal.y1+2*lambda, metal.x2, metal.y2], inst.ob.layer]; CDDraw[metal, met]; CDDraw[[metal.x1+lambda, metal.y1+lambda, metal.x2-lambda, metal.y2-lambda], cut]; END END; Init[]; END.