<> <> <> <<>> DIRECTORY CD, CDRects, CDSatellites, CDSimpleRules, CDTexts, CMosB, CMosBObjects, Core, CoreClasses, CoreGeometry, CoreOps, CoreProperties, CoreRoute, DataPath, IO, PW, PWCore, Rope, Sisyph, TerminalIO; DataPathMuxVPwr: CEDAR PROGRAM IMPORTS CDRects, CDSatellites, CDSimpleRules, CDTexts, CMosB, CMosBObjects, CoreGeometry, CoreOps, CoreProperties, CoreRoute, DataPath, IO, PW, PWCore, Rope, Sisyph, TerminalIO = BEGIN <> Signal: SIGNAL = CODE; MuxForm: TYPE = REF MuxFormRec; MuxFormRec: TYPE = RECORD[in, top, bot, ctl, out: Wire]; Wire: TYPE = Core.Wire; Wires: TYPE = Core.Wires; CellType: TYPE = Core.CellType; muxFormProp: ATOM _ $DataPathForm; blank: Wire _ CoreOps.CreateWires[0, "Blank"]; textScale: INT _ 2; font: CDTexts.CDFont _ CDTexts.MakeFont["Xerox/TiogaFonts/Helvetica7", textScale]; dwText: CD.Object _ CDTexts.Create["driveWeak", font]; Vdd: IO.ROPE _ "Vdd"; Gnd: IO.ROPE _ "Gnd"; plus: IO.ROPE _ "+"; minus: IO.ROPE _ "-"; log: IO.STREAM _ TerminalIO.TOS[]; lambda: INT _ CMosB.lambda; topTail: INT _ 2* lambda; botTail: INT _ 1* lambda; cnctSize: INT _ 4* lambda; layRules: ATOM _ $cmosB; schDeco: CoreGeometry.Decoration _ Sisyph.mode.decoration; layDeco: CoreGeometry.Decoration _ PWCore.extractMode.decoration; <> <> <> <<1. Write an extract proc for multiplexors (which would provide the names).>> <<2. Write a variation of PWCore.DecorateValue that used some other property on the source public to do the binding.>> <<3. Require that the designer always put valid names in the mux schematic.>> <> MuxAttributes: PWCore.AttributesProc = { OPEN CG: CoreGeometry; spec: DataPath.DPSpec _ DataPath.NewCellTypeSpec[cellType]; data: CoreClasses.RecordCellType _ NARROW[cellType.data]; wires: Wires; gnd: Wire _ CoreOps.FindWire[cellType.public, "Gnd"]; vdd: Wire _ CoreOps.FindWire[cellType.public, "Vdd"]; form: MuxForm _ NEW[MuxFormRec]; char: CHAR _ 'a; EachSideWire: CG.EachSortedPinProc = {wires _ CONS[wire, wires]}; EachChanWire: CG.EachSortedPinProc = { -- wire min max layer count: INT _ 0; chan: INT _ (DataPath.SchHalfBus[spec, (min+max)/2]-1)/2; FOR ws: Wires _ wires, ws.rest WHILE ws#NIL DO count _ count+1 ENDLOOP; FOR chanIndex: INT IN (count..chan] DO wires _ CONS[blank, wires] ENDLOOP; wires _ CONS[wire, wires]}; InsertGndVdd: PROC[orig: Wires] RETURNS[new: Wires _ NIL] = { FOR index: INT _ 0, index + 1 DO next: Wire; IF MAX[spec.gndBus, spec.vddBus] < index AND orig=NIL THEN EXIT; SELECT TRUE FROM index = spec.gndBus => {next _ gnd; IF gnd=NIL THEN ERROR}; index = spec.vddBus => {next _ vdd; IF vdd=NIL THEN ERROR}; orig#NIL => {next _ orig.first}; ENDCASE => {next _ blank}; IF orig#NIL THEN {IF next#orig.first AND orig.first#blank THEN ERROR; orig _ orig.rest}; new _ CONS[next, new]; ENDLOOP; RETURN[CoreOps.Reverse[new]]}; Name: PROC[w: Wire, prefix: IO.ROPE, index: INT] = { IF CoreOps.GetShortWireName[w].Length[]=0 THEN { nm: IO.ROPE _ IO.PutFR["%g%g", IO.rope[prefix], IO.int[index]]; CheckForConflict: CoreOps.EachWireProc = {IF nm.Equal[CoreOps.GetShortWireName[wire]] THEN ERROR}; []_CoreOps.VisitWire[cellType.public, CheckForConflict]; []_CoreOps.SetShortWireName[w, nm]}}; wires _ NIL; []_CG.EnumerateSortedSides[schDeco, cellType, top, EachChanWire]; form.top _ CoreOps.CreateWire[InsertGndVdd[ CoreOps.Reverse[wires]]]; wires _ NIL; []_CG.EnumerateSortedSides[schDeco, cellType, bottom, EachChanWire]; form.bot _ CoreOps.CreateWire[InsertGndVdd[ CoreOps.Reverse[wires]]]; wires _ NIL; []_CG.EnumerateSortedSides[schDeco, cellType, left, EachSideWire]; form.ctl _ CoreOps.CreateWire[CoreOps.Reverse[wires]]; form.in _ CoreOps.CreateWires[form.ctl.size]; FOR child: NAT IN [0..data.size) DO gate: Wire _ data[child].actual[CoreOps.GetWireIndex[data[child].type.public, "gate"]]; ch1: Wire _ data[child].actual[CoreOps.GetWireIndex[data[child].type.public, "ch1"]]; ch2: Wire _ data[child].actual[CoreOps.GetWireIndex[data[child].type.public, "ch2"]]; FOR index: INT IN [0..form.ctl.size) DO IF form.ctl[index]#gate THEN LOOP; IF form.in[index]#NIL THEN Signal[]; form.in[index] _ ch1; IF form.out#NIL AND form.out#ch2 THEN Signal[]; form.out _ ch2; EXIT REPEAT FINISHED=> Signal[] ENDLOOP; ENDLOOP; FOR i: NAT IN [0..form.ctl.size) DO Name[form.ctl[i], "ctl", i] ENDLOOP; FOR i: NAT IN [0..form.in.size) DO Name[form.in[i], "in", i] ENDLOOP; FOR i: NAT IN [0..form.top.size) DO Name[form.top[i], "top", i] ENDLOOP; FOR i: NAT IN [0..form.bot.size) DO Name[form.bot[i], "bot", i] ENDLOOP; Name[form.out, "out", 0]; CoreOps.FlushNameCaches[cellType.public]; CoreOps.FlushNameCaches[data.internal]; CoreProperties.PutCellTypeProp[cellType, muxFormProp, form]}; MuxLayout: PWCore.LayoutProc = { spec: DataPath.DPSpec _ DataPath.NewCellTypeSpec[cellType]; data: CoreClasses.RecordCellType _ NARROW[cellType.data]; f: MuxForm _ NARROW[CoreProperties.GetCellTypeProp[cellType, muxFormProp]]; name: IO.ROPE _ CoreOps.GetCellTypeName[cellType]; insts: CD.InstanceList _ NIL; cellWidth: INT _ DataPath.BitWidth[spec]; xstrLgth: INT _ 8*lambda; xstrWth: INT _ (4+4)*lambda; xstrWthBig: INT _ (4+8)*lambda; tranBiasx: INT _ (xstrWth-spec.metW)/2; tranBiasLtx: INT _ tranBiasx + 4*lambda; xstrHt: INT _ xstrLgth + 2*spec.difW; pFrng: INT _ (spec.pwrW-spec.metW)/2; topExtra: INT _ cnctSize/2 + topTail; botExtra: INT _ cnctSize/2 + botTail; cnctBiasx: INT _ (cnctSize-spec.metW)/2; viaPolSpace: INT _ 3*cnctSize; -- actually 2+4+1+4+1 lambda muxEvenDn: BOOL = TRUE; minTranUsd: BOOL _ FALSE; gnd: INT _ spec.gndBus; vdd: INT _ spec.vddBus; rangeXMax: INT _ spec.buses+(spec.layDWidth - viaPolSpace)/spec.layBusW; range: CD.Position _ [MIN[rangeXMax, MAX[f.top.size, f.bot.size]+1], f.ctl.size]; pitch: CD.Position _ [spec.metPitch, spec.met2Pitch]; <> outIndex: INT _ WireIndexMax[f.top, f.out]; outIndexBot: INT _ WireIndexMax[f.bot, f.out]; IF outIndex # WireIndexMin[f.top, f.out] OR outIndexBot # WireIndexMin[f.bot, f.out] OR outIndex#-1 AND outIndexBot#-1 AND outIndex#outIndexBot THEN {log.PutF["*** Multiple column output\n"]; ERROR}; outIndex _ MAX[outIndex, outIndexBot]; IF f.out#blank AND WireIndexMax[f.in, f.out]#-1 THEN {log.PutF["*** Output signal is also used as input\n"]; ERROR}; <<>> <> FOR i: INT IN [0..range.x) DO loc: CD.Position _ [i*pitch.x, 0]; topOut: BOOL _ f.out # blank AND IW[f.top, i] = f.out; botOut: BOOL _ f.out # blank AND IW[f.bot, i] = f.out; tY: INT _ IF topOut THEN WireNonBlankIndexMin[f.in] ELSE WireIndexMin[f.in, IW[f.top, i]]; bY: INT _ IF botOut THEN WireNonBlankIndexMax[f.in] ELSE WireIndexMax[f.in, IW[f.bot, i]]; tY _ tY + ((tY + (IF topOut=muxEvenDn THEN 1 ELSE 2)) MOD 2); bY _ bY + ((bY + (IF botOut=muxEvenDn THEN 1 ELSE 2)) MOD 2); IF tY=-1 AND bY=-1 THEN tY_bY_0; IF ~(IW[f.top, i] = IW[f.bot, i]) AND tY<=bY AND IW[f.top, i]#blank AND IW[f.bot, i]#blank THEN {log.PutF["*** 2 signals in same channel\n"]; ERROR}; IF IW[f.top, i]#blank THEN insts _ AddRetInst[ insts: insts, internal: data.internal, wire: f.top[i], level: CMosB.met, size: [spec.metW, (range.y-tY) * pitch.y + topExtra ], loc: [i*pitch.x, tY * pitch.y ]]; IF IW[f.bot, i]#blank THEN insts _ AddRetInst[ insts: insts, internal: data.internal, wire: f.bot[i], level: CMosB.met, size: [spec.metW, bY * pitch.y + botExtra ], loc: [i*pitch.x, 0 * pitch.y - botExtra ]]; ENDLOOP; IF gnd>-1 THEN { gndWire: Wire _ CoreOps.FindWire[data.internal, "Gnd"]; insts _ AddRetInst[ insts: insts, internal: data.internal, wire: gndWire, level: CMosB.met, size: [spec.pwrW, range.y * pitch.y + topExtra + botExtra ], loc: [gnd*pitch.x-pFrng , - botExtra ]]}; IF vdd>-1 THEN { vddWire: Wire _ CoreOps.FindWire[data.internal, "Vdd"]; insts _ AddRetInst[ insts: insts, internal: data.internal, wire: vddWire, level: CMosB.met, size: [spec.pwrW, range.y * pitch.y + topExtra + botExtra ], loc: [vdd*pitch.x-pFrng , - botExtra ]]}; BEGIN xstr: CD.Object _ CMosBObjects.CreateTransistor [size: [xstrWth, xstrLgth], difLayer: CMosB.ndif]; xstrBig: CD.Object _ CMosBObjects.CreateTransistor [size: [xstrWthBig, xstrLgth], difLayer: CMosB.ndif]; dcon: CD.Object _ CDSimpleRules.Contact[layRules, CMosB.met, CMosB.ndif]; pcon: CD.Object _ CDSimpleRules.Contact[layRules, CMosB.met, CMosB.pol]; vcon: CD.Object _ CDSimpleRules.Contact[layRules, CMosB.met, CMosB.met2]; scon: CD.Object _ CMosBObjects.CreateDifCon[CMosB.pwellCont]; pvconn: CD.Object _ CDRects.CreateRect[[2*cnctSize, cnctSize], CMosB.met]; lstIONotGnd: BOOL _ TRUE; lstGndClear: BOOL _ TRUE; thsIONotGnd: BOOL _ TRUE; thsGndClear: BOOL _ TRUE; FOR ctlIndex: INT IN [0..range.y) DO Include: PROC[object: CD.Object, location: CD.Position] = {insts _ CONS[ NEW[CD.InstanceRep _ [object, [location]]], insts]}; AddGndContact: PROC[updn: {up, dn}] = {IF updn=up THEN Include[scon, [gnd*pitch.x-cnctBiasx, (ctlIndex+1)*pitch.y-cnctSize/2]] ELSE Include[scon, [gnd*pitch.x-cnctBiasx, (ctlIndex+0)*pitch.y-cnctSize/2]]}; AddMux: PROC [index: CD.Position, lt, rt: BOOL] = { dWL: INT _ (ABS[outIndex-index.x])*pitch.x+cnctSize; pWL: INT _ (range.x-index.x)*pitch.x; minX: INT _ MIN[outIndex, index.x]; polX: INT _ MIN[outIndex, index.x]; pol: CD.Object _ CDRects.CreateRect[[pWL, spec.polW], CMosB.pol]; dif: CD.Object _ CDRects.CreateRect[[dWL, spec.difW], CMosB.ndif]; dir: INT _ IF ((index.y MOD 2)=0)=muxEvenDn THEN 1 ELSE -1; yloc: INT _ index.y*pitch.y + pitch.y/2; Include[pcon, [range.x *pitch.x -cnctBiasx, yloc -cnctSize/2 ]]; Include[pvconn, [range.x *pitch.x -cnctBiasx, yloc -cnctSize/2 ]]; Include[vcon, [range.x *pitch.x -cnctBiasx+cnctSize+lambda, yloc -cnctSize/2 ]]; Include[pol, [index.x *pitch.x -cnctBiasx, yloc -spec.polW/2 ]]; Include[dif, [minX *pitch.x -cnctBiasx, yloc +dir*pitch.y/2 -spec.difW/2 ]]; Include[dcon, [outIndex *pitch.x -cnctBiasx, yloc +dir*pitch.y/2 -cnctSize/2 ]]; Include[dcon, [index.x *pitch.x -cnctBiasx, yloc -dir*pitch.y/2 -cnctSize/2 ]]; Include[dwText, [index.x *pitch.x -tranBiasx, yloc -lambda*textScale/2 ]]; SELECT TRUE FROM lt => Include[xstrBig, [index.x *pitch.x -tranBiasLtx, yloc -xstrLgth/2 ]]; rt => Include[xstrBig, [index.x *pitch.x -tranBiasx, yloc -xstrLgth/2 ]]; ENDCASE => Include[xstr, [index.x *pitch.x -tranBiasx, yloc -xstrLgth/2 ]]; CDSatellites.Associate[master: insts.first, text: insts.rest.first]}; size: CD.Position _ [DataPath.BitWidth[spec], spec.met2W]; loc: CD.Position _ [spec.metW/2-spec.leftTail, ctlIndex*pitch.y+pitch.y/2-spec.met2W/2]; insts _ AddRetInst[insts: insts, internal: data.internal, wire: f.ctl[ctlIndex], size:size, loc:loc, level: CMosB.met2]; IF f.out#blank THEN { ioIndex: INT _ IOIndex[ctlIndex, f]; IF ioIndex >=0 THEN { <> inDn: BOOL _ ((ctlIndex MOD 2)=0)=muxEvenDn; <> ioIndexUp: INT _ IF inDn THEN -1 ELSE IOIndex[ctlIndex+1, f]; ioIndexDn: INT _ IF ~inDn THEN -1 ELSE IOIndex[ctlIndex-1, f]; extLt: BOOL _ ioIndex # (gnd+1) AND ioIndex # 0 AND (ioIndexUp=-1 OR ioIndexUp#(ioIndex-1)) AND (ioIndexDn=-1 OR ioIndexDn#(ioIndex-1)); extRt: BOOL _ ioIndex # (gnd-1) AND ioIndex < (range.x-1) AND (ioIndexUp=-1 OR ioIndexUp#(ioIndex+1)) AND (ioIndexDn=-1 OR ioIndexDn#(ioIndex+1)); IF NOT(extLt OR extRt) THEN minTranUsd _ TRUE; AddMux[[ioIndex, ctlIndex], extLt, extRt]}; thsIONotGnd _ ioIndex # gnd; thsGndClear _ thsIONotGnd AND ((ioIndex> IOIndex: PROC[ctl: INT, form: MuxForm] RETURNS[ioIndex: INT] = { IF ctl NOT IN[0..form.in.size) THEN RETURN[-1]; IF form.in[ctl]=blank THEN RETURN[-1]; ioIndex _ WireIndexMax[form.top, form.in[ctl]]; IF ioIndex > -1 THEN RETURN[ioIndex]; ioIndex _ WireIndexMax[form.bot, form.in[ctl]]}; IW: PROC[wire: Wire, index: INT] RETURNS[subwire: Wire] = {RETURN[IF index IN [0..wire.size) THEN wire[index] ELSE blank]}; WireIndexMax: PROC[root, subWire: Wire] RETURNS[index: INT _ -1] = {FOR i: INT DECREASING IN [0..root.size) DO IF root[i]=subWire THEN RETURN[i] ENDLOOP}; WireIndexMin: PROC[root, subWire: Wire] RETURNS[index: INT _ -1] = {FOR i: INT IN [0..root.size) DO IF root[i]=subWire THEN RETURN[i] ENDLOOP}; WireNonBlankIndexMin: PUBLIC PROC [wire: Wire] RETURNS[index: INT] = { FOR index IN [0..wire.size) DO IF wire[index]#blank THEN RETURN[index] ENDLOOP; RETURN[-1]}; WireNonBlankIndexMax: PUBLIC PROC [wire: Wire] RETURNS[index: INT] = { FOR index DECREASING IN [0..wire.size) DO IF wire[index]#blank THEN RETURN[index] ENDLOOP; RETURN[-1]}; <<>> AddRetInst: PROC[insts: CD.InstanceList, internal, wire: Wire, size: CD.Position, loc: CD.Position, level: CD.Layer] RETURNS[CD.InstanceList] = { name: IO.ROPE _ CoreRoute.LabelInternal[internal, wire]; props: CD.PropList _ LIST[[$SignalName, name]]; IF size.x<0 OR size.y<0 THEN { log.PutF["*** Strange rectangle size [%g, %g]\n", IO.int[size.x], IO.int[size.y] ]; Signal[]}; IF size.x=0 OR size.y=0 THEN RETURN[insts]; insts _ CONS[ NEW[CD.InstanceRep _ [ ob: CDRects.CreateRect[size, level], trans: [loc], properties: props ]], insts]; RETURN[insts]}; <> [] _ PWCore.RegisterLayoutAtom [$DPMuxVPwr, MuxLayout, PWCore.DecorateValue, MuxAttributes]; END.