<> <> <> <> DIRECTORY CD, Convert, EuControl, PW, PWDescr, Rope, SymTab; EuControlImpl: CEDAR PROGRAM IMPORTS Convert, PW, PWDescr, Rope, SymTab EXPORTS EuControl = BEGIN OPEN EuControl; <<>> <<--User-level routines for describing control in this style of design: nand precharged decoder>> <<-- Integers and bools are represented by pairs of wires, bits (not bools) on a single wire>> ControlProc: TYPE = PROC [design: CD.Design, descr: PWDescr.Descriptor] RETURNS [obj: PW.ObPtr]; <<-- A generic proc that turns a descriptor into some part of the control>> ControlLine: PROC [design: CD.Design, descrPD, descrPU: PWDescr.Descriptor, DescrToPD, DescrToPU: ControlProc, gnd, sep, driver: PW.ObPtr, name: ROPE, flipY: BOOL _ FALSE] RETURNS [controlLine: PW.ObPtr] = BEGIN controlLine _ PW.AbutX[design, gnd, DescrToPD[design, descrPD], sep, DescrToPU[design, descrPU], driver]; IF flipY THEN controlLine _ PW.FlipY[design, controlLine]; PW.RenameObject[design, controlLine, "name"]; END; <<-- Assemble pieces into a NAND decoder>> Nand: PUBLIC PROC [design: CD.Design, descrPD, descrPU: PWDescr.Descriptor, flipY: BOOL _ FALSE] RETURNS [nandDec: PW.ObPtr] = {nandDec _ ControlLine[design, descrPD, descrPU, DescrToNandPD, DescrToNandPU, decGround, decNPSep, decDriver, "nandDec", flipY]}; <<>> <<-- A wire or set of wires routing a particular item to the datapath (right side)>> RouteTo: PUBLIC PROC [design: CD.Design, descrPD, descrPU: PWDescr.Descriptor] RETURNS [wire: PW.ObPtr] = {wire _ ControlLine[design, descrPD, descrPU, DescrToWirePD, DescrToWirePU, decWireGround, decWireNPSep, decWireDriver, "wire"]}; <<-- Bias voltage generator>> BiasVoltage: PUBLIC PROC [design: CD.Design, descrPD, descrPU: PWDescr.Descriptor] RETURNS [bias: PW.ObPtr] = {bias _ ControlLine[design, descrPD, descrPU, DescrToWirePD, DescrToWirePU, decWireGround, decWireNPSep, decBiasVoltage, "biasVoltage"]}; <<>> <<-- A set of inverters computing the complementary of signals specified by the descriptor>> Inverters: PUBLIC PROC [design: CD.Design, descrPD, descrPU: PWDescr.Descriptor, flipY: BOOL _ FALSE] RETURNS [inverters: PW.ObPtr] = {inverters _ ControlLine[design, descrPD, descrPU, DescrToInvPD, DescrToInvPU, decInvGround, devInvNPSep, decInvDriver, "inverters", flipY]}; <<-- A separations between two control parts having different descriptors of the same size; the semantic is the same as the routing, but specifies whether a wire is interrupted or not; if metal2 is used to double poly, this is the place to contact both layers>> Gap: PUBLIC PROC [design: CD.Design, descrPD, descrPU: PWDescr.Descriptor, flipY: BOOL _ FALSE] RETURNS [gap: PW.ObPtr] = {gap _ ControlLine[design, descrPD, descrPU, DescrToGapPD, DescrToGapPU, decGapGround, decGapNPSep, decGapDriver, "gap", flipY]}; <<>> <<-- A set of NAND decoders, grouped as pull-downs of a precharged NOR; each branch has a different pull-down descriptor, but there is only one pull-up descriptor>> NorOfNands: PUBLIC PROC [design: CD.Design, listDescrPD: LIST OF PWDescr.Descriptor, descrPU: PWDescr.Descriptor, flipY: BOOL _ FALSE] RETURNS [norDec: PW.ObPtr] = BEGIN flipBranch: BOOL _ TRUE; listBranch: PW.ListOb _ CONS[Nand[design, listDescrPD.first, descrPU]]; FOR l: LIST OF PWDescr.Descriptor _ listDescrPD.rest, l.rest WHILE l#NIL DO listBranch _ CONS[NorBranch[design, l.first, descrPU, flipBranch], listBranch]; flipBranch _ ~flipBranch; ENDLOOP; norDec _ PW.AbutListY[design, listBranch]; IF flipY THEN norDec _ PW.FlipY[design, norDec]; PW.RenameObject[design, norDec, "norDec"]; END; <<>> NorBranch: PROC [design: CD.Design, descrPD, descrPU: PWDescr.Descriptor, flipY: BOOL _ FALSE] RETURNS [branch: PW.ObPtr] = {branch _ ControlLine[design, descrPD, descrPU, DescrToNandPD, DescrToNandPU, decGround, decNPSep, IF flipY THEN norDecAttachDown ELSE norDecAttachUp, "branch", flipY]}; <<>> <<-- Internal routines for generating control>> <<-- Descriptor to pull-down chain>> DescrToNandPD: PROC [design: CD.Design, descr: PWDescr.Descriptor] RETURNS [obj: PW.ObPtr _ NIL] = BEGIN listOb: PW.ListOb _ NIL; BoolToPD: PROC [bool: PWDescr.BoolRef] RETURNS [obj: PW.ObPtr] = {obj _ SELECT TRUE FROM ~bool.val0 AND ~bool.val1 => decX, bool.val0 AND ~bool.val1 => decOne, ~bool.val0 AND bool.val1 => decZero, ENDCASE => ERROR}; -- both bits=1 has no meaning here IntToPD: PROC [int: PWDescr.IntRef] RETURNS [obj: PW.ObPtr] = BEGIN found: BOOL; ref: SymTab.Val; -- check the order of bits IntToObj: PW.XYFunction = {RETURN[BoolToPD[int.bools[x]]]}; uniqueID: INT _ int.nbBits+100*int.val+10000*int.mask; key: ROPE _ Rope.Concat["PD", Convert.RopeFromInt[uniqueID]]; [found, ref] _ SymTab.Fetch[cellCache, key]; IF ~found THEN { obj _ PW.MapFunctionX[design, IntToObj, 0, int.nbBits]; [] _ SymTab.Store[cellCache, key, obj];} ELSE obj _ NARROW[ref]; END; forEachItem: PWDescr.ForEachItemProc = {obj: PW.ObPtr _ WITH item.specificRef SELECT FROM bit: PWDescr.BitRef => obj _ IF bit.val THEN decTransistor ELSE decNoTransistor, bool: PWDescr.BoolRef => obj _ BoolToPD[bool], int: PWDescr.IntRef => obj _ IntToPD[int], ENDCASE => ERROR; listOb _ CONS[obj, listOb];}; PWDescr.EnumerateItems[descr, forEachItem]; obj _ PW.AbutListX[design, PW.Reverse[listOb]]; END; <<-- Descriptor to pull-up chain: different from DescrToPD because not only the cells, but also the assembly process is different (flip)>> DescrToNandPU: PROC [design: CD.Design, descr: PWDescr.Descriptor] RETURNS [obj: PW.ObPtr _ NIL] = BEGIN listOb: PW.ListOb _ NIL; forEachItem: PWDescr.ForEachItemProc = {obj: PW.ObPtr _ WITH item.specificRef SELECT FROM bit: PWDescr.BitRef => obj _ IF bit.val THEN (IF flip THEN decPTransFlip ELSE decPTrans) ELSE (IF flip THEN decPNoTransFlip ELSE decPNoTrans), ENDCASE => ERROR; listOb _ CONS[obj, listOb]; flip _ ~flip;}; flip: BOOL _ FALSE; PWDescr.EnumerateItems[descr, forEachItem]; obj _ PW.AbutListX[design, PW.Reverse[listOb]]; END; <<>> <<-- Descriptor to wire routing to a particular item in the descriptor: only one bit is wired.>> DescrToWirePD: PROC [design: CD.Design, descr: PWDescr.Descriptor] RETURNS [wire: PW.ObPtr _ NIL] = BEGIN listOb: PW.ListOb _ NIL; BoolToWire: PROC [bool: PWDescr.BoolRef] RETURNS [obj: PW.ObPtr] = {obj _ SELECT TRUE FROM ~bool.val0 AND ~bool.val1 => decWireX, bool.val0 AND ~bool.val1 => decWireZeroCt, ~bool.val0 AND bool.val1 => decWireOneCt, ENDCASE => ERROR}; IntToWire: PROC [int: PWDescr.IntRef] RETURNS [obj: PW.ObPtr] = BEGIN found: BOOL; ref: SymTab.Val; IntToAdrFn: PW.XYFunction = {RETURN[BoolToWire[int.bools[x]]]}; uniqueID: INT _ int.nbBits+100*int.val+10000*int.mask; key: ROPE _ Rope.Concat["W", Convert.RopeFromInt[uniqueID]]; [found, ref] _ SymTab.Fetch[cellCache, key]; IF ~found THEN { obj _ PW.MapFunctionX[design, IntToAdrFn, 0, int.nbBits]; [] _ SymTab.Store[cellCache, key, obj];} ELSE obj _ NARROW[ref]; END; forEachItemMakeWire: PWDescr.ForEachItemProc = BEGIN obj: PW.ObPtr _ WITH item.specificRef SELECT FROM bit: PWDescr.BitRef => IF bit.val THEN decWireCt ELSE decWireNoCt, bool: PWDescr.BoolRef => BoolToWire[bool], int: PWDescr.IntRef => IntToWire[int], ENDCASE => ERROR; listOb _ CONS[obj, listOb]; END; PWDescr.EnumerateItems[descr, forEachItemMakeWire]; wire _ PW.AbutListX[design, PW.Reverse[listOb]]; END; <<-- so far, we find only bits in a pull-up>> DescrToWirePU: PROC [design: CD.Design, descr: PWDescr.Descriptor] RETURNS [wire: PW.ObPtr _ NIL] = BEGIN listOb: PW.ListOb _ NIL; forEachItemMakeWire: PWDescr.ForEachItemProc = BEGIN obj: PW.ObPtr _ WITH item.specificRef SELECT FROM bit: PWDescr.BitRef => IF bit.val THEN decWirePCt ELSE decWirePNoCt, ENDCASE => ERROR; IF flip THEN listOb _ CONS[PW.FlipX[design, obj], listOb] ELSE listOb _ CONS[obj, listOb]; flip _ ~flip; END; flip: BOOL _ FALSE; PWDescr.EnumerateItems[descr, forEachItemMakeWire]; wire _ PW.AbutListX[design, PW.Reverse[listOb]]; END; <<-- Descriptor to pull-down chain>> DescrToInvPD: PROC [design: CD.Design, descr: PWDescr.Descriptor] RETURNS [obj: PW.ObPtr _ NIL] = BEGIN listOb: PW.ListOb _ NIL; BoolToPD: PROC [bool: PWDescr.BoolRef] RETURNS [obj: PW.ObPtr] = {obj _ IF bool.val0 THEN decInv ELSE decNoInv2}; IntToPD: PROC [int: PWDescr.IntRef] RETURNS [obj: PW.ObPtr] = BEGIN -- check the order of bits IntToObj: PW.XYFunction = {RETURN[BoolToPD[int.bools[x]]]}; obj _ PW.MapFunctionX[design, IntToObj, 0, int.nbBits]; END; forEachItem: PWDescr.ForEachItemProc = {obj: PW.ObPtr _ WITH item.specificRef SELECT FROM bit: PWDescr.BitRef => obj _ decNoInv, bool: PWDescr.BoolRef => obj _ BoolToPD[bool], int: PWDescr.IntRef => obj _ IntToPD[int], ENDCASE => ERROR; listOb _ CONS[obj, listOb];}; PWDescr.EnumerateItems[descr, forEachItem]; obj _ PW.AbutListX[design, PW.Reverse[listOb]]; END; <<-- Descriptor to pull-up chain: different from DescrToPD because not only the cells, but also the assembly process is different (flip)>> DescrToInvPU: PROC [design: CD.Design, descr: PWDescr.Descriptor] RETURNS [obj: PW.ObPtr _ NIL] = BEGIN listOb: PW.ListOb _ NIL; forEachItem: PWDescr.ForEachItemProc = {obj: PW.ObPtr _ WITH item.specificRef SELECT FROM bit: PWDescr.BitRef => obj _ IF flip THEN decInvPFlip ELSE decInvP, ENDCASE => ERROR; listOb _ CONS[obj, listOb]; flip _ ~flip;}; flip: BOOL _ FALSE; PWDescr.EnumerateItems[descr, forEachItem]; obj _ PW.AbutListX[design, PW.Reverse[listOb]]; END; <<>> <<-- Descriptor to gap. All the wires of an item are passed together>> DescrToGapPD: PROC [design: CD.Design, descr: PWDescr.Descriptor] RETURNS [gap: PW.ObPtr _ NIL] = BEGIN listOb: PW.ListOb _ NIL; BoolToGap: PROC [bool: PWDescr.BoolRef] RETURNS [obj: PW.ObPtr] = {obj _ IF ~bool.val0 THEN decPassX ELSE decPass2}; IntToGap: PROC [int: PWDescr.IntRef] RETURNS [obj: PW.ObPtr] = BEGIN IntToAdrFn: PW.XYFunction = {RETURN[BoolToGap[int.bools[x]]]}; obj _ PW.MapFunctionX[design, IntToAdrFn, 0, int.nbBits]; END; forEachItemMakeWire: PWDescr.ForEachItemProc = BEGIN obj: PW.ObPtr _ WITH item.specificRef SELECT FROM bit: PWDescr.BitRef => IF bit.val THEN decGapPass ELSE decGapNoPass, bool: PWDescr.BoolRef => BoolToGap[bool], int: PWDescr.IntRef => IntToGap[int], ENDCASE => ERROR; listOb _ CONS[obj, listOb]; END; PWDescr.EnumerateItems[descr, forEachItemMakeWire]; gap _ PW.AbutListX[design, PW.Reverse[listOb]]; END; <<-- so far, we find only bits in a pull-up>> DescrToGapPU: PROC [design: CD.Design, descr: PWDescr.Descriptor] RETURNS [gap: PW.ObPtr _ NIL] = BEGIN listOb: PW.ListOb _ NIL; forEachItemMakeWire: PWDescr.ForEachItemProc = BEGIN obj: PW.ObPtr _ WITH item.specificRef SELECT FROM bit: PWDescr.BitRef => IF bit.val THEN decGapPPass ELSE decGapPNoPass, ENDCASE => ERROR; IF flip THEN listOb _ CONS[PW.FlipX[design, obj], listOb] ELSE listOb _ CONS[obj, listOb]; flip _ ~flip; END; flip: BOOL _ FALSE; PWDescr.EnumerateItems[descr, forEachItemMakeWire]; gap _ PW.AbutListX[design, PW.Reverse[listOb]]; END; <<>> <<>> <<-- A speed-up hack>> cellCache: SymTab.Ref; <<>> <<-- Pull-down of the Nand/Nor of Nand decoder>> decGround, decTransistor, decNoTransistor, decZero, decOne, decX: PW.ObPtr; <<-- Pull-up of the Nand/Nor of Nand decoder>> decNPSep, decPNoTrans, decPNoTransFlip, decPTrans, decPTransFlip, decLeftPrech, decRightPrech, decDriver, norDecAttachUp, norDecAttachDown: PW.ObPtr; <<-- Pull-down part of a wire>> decWireGround, decWireCt, decWireNoCt, decWireZeroCt, decWireOneCt, decWireX: PW.ObPtr; <<-- Pull-up part of a wire, and a special case for the bias voltage generator>> decWireNPSep, decWirePCt, decWirePNoCt, decWirePrechNoCt, decWirePrechLeftCt, decWirePrechRightCt, decWireDriver, decBiasVoltage: PW.ObPtr; <<-- Pull-down part of an inverter>> decInvGround, decNoInv, decNoInv2, decInv, decInvPFlip: PW.ObPtr; <<-- Pull-up part of an inverter>> devInvNPSep, decInvP, decInvDriver: PW.ObPtr; <<-- Pull-down part of a gap>> decGapGround, decGapPass, decGapNoPass, decPassX, decPass2: PW.ObPtr; <<-- Pull-up part of a gap>> decGapNPSep, decGapPPass, decGapPNoPass, decGapDriver: PW.ObPtr; <<>> InitEUControl: PUBLIC PROC [design: CD.Design] = BEGIN PW.SetDefaultSource[design, PW.OpenDesign["///eulayout.dale"]]; decTransistor _ PW.Get[design, "decTransistor"]; decNoTransistor _ PW.Get[design, "decNoTransistor"]; decDriver _ PW.Get[design, "decDriver"]; norDecAttachUp _ PW.Get[design, "norDecAttachUp"]; norDecAttachDown _ PW.Get[design, "norDecAttachDown"]; decPNoTrans _ PW.Get[design, "decPNoTrans"]; decPNoTransFlip _ PW.FlipX[design, decPNoTrans]; decPTrans _ PW.Get[design, "decPTrans"]; decPTransFlip _ PW.FlipX[design, decPTrans]; decNPSep _ PW.Get[design, "decNPSep"]; decGround _ PW.Get[design, "decGround"]; decZero _ PW.AbutX[design, decNoTransistor, decTransistor]; -- convention!!! decOne _ PW.AbutX[design, decTransistor, decNoTransistor]; decX _ PW.AbutX[design, decNoTransistor, decNoTransistor]; decLeftPrech _ PW.AbutX[design, decPTrans, decPNoTransFlip]; decRightPrech _ PW.AbutX[design, decPNoTrans, decPTransFlip]; decWireCt _ PW.Get[design, "decWireCt"]; decWireNoCt _ PW.Get[design, "decWireNoCt"]; decWireZeroCt _ PW.AbutX[design, decWireCt, decWireNoCt]; decWireOneCt _ PW.AbutX[design, decWireNoCt, decWireCt]; decWireX _ PW.AbutX[design, decWireNoCt, decWireNoCt]; decWireNPSep _ PW.Get[design, "decWireNPSep"]; decWirePCt _ PW.Get[design, "decWirePCt"]; decWirePNoCt _ PW.Get[design, "decWirePNoCt"]; decWireDriver _ PW.Get[design, "decWireDriver"]; decBiasVoltage _ PW.Get[design, "decBiasVoltage"]; decWireGround _ PW.Get[design, "decWireGround"]; decWirePrechNoCt _ PW.AbutX[design, decWirePNoCt, PW.FlipX[design, decWirePNoCt]]; decWirePrechLeftCt _ PW.AbutX[design, decWirePCt, PW.FlipX[design, decWirePNoCt]]; decWirePrechRightCt _ PW.AbutX[design, decWirePNoCt, PW.FlipX[design, decWirePCt]]; decInvGround _ PW.Get[design, "decInvGround"]; decNoInv _ PW.Get[design, "decNoInv"]; decNoInv2 _ PW.AbutX[design, decNoInv, decNoInv]; decInv _ PW.Get[design, "decInv"]; devInvNPSep _ PW.Get[design, "devInvNPSep"]; decInvP _ PW.Get[design, "decInvP"]; decInvPFlip _ PW.FlipX[design, decInvP]; decInvDriver _ PW.Get[design, "decInvDriver"]; decGapGround _ PW.Get[design, "decGapGround"]; decGapPass _ PW.Get[design, "decGapPass"]; decGapNoPass _ PW.Get[design, "decGapNoPass"]; decPassX _ PW.AbutX[design, decGapNoPass, decGapNoPass]; decPass2 _ PW.AbutX[design, decGapPass, decGapPass]; decGapNPSep _ PW.Get[design, "decGapNPSep"]; decGapPPass _ PW.Get[design, "decGapPPass"]; decGapPNoPass _ PW.Get[design, "decGapPNoPass"]; decGapDriver _ PW.Get[design, "decGapDriver"]; cellCache _ SymTab.Create[mod: 67]; END; <<>> <<>> <<>> END. <<>>