<> <> <> <> <<>> DIRECTORY CCDUtils, CD, CDBasics, CDCells, CDRects, CDSatellites, CDTexts, Core, CoreClasses, CoreCreate, CoreFrame, CoreLibrary, CoreName, CoreOps, CoreWire, CoreXform, IFUCoreCells, IFUCoreData, CoreInstCell, IO, Lists, Rope; IFUCoreDataMuxImpl: CEDAR PROGRAM IMPORTS CCDUtils, CD, CDBasics, CDCells, CDRects, CDSatellites, CDTexts, CoreCreate, CoreFrame, CoreLibrary, CoreName, CoreOps, CoreWire, CoreXform, IFUCoreCells, IFUCoreData, CoreInstCell, IO, Lists, Rope = BEGIN OPEN CCDUtils; ROPE: TYPE = Core.ROPE; VDD: ROPE _ CoreName.RopeNm["VDD"]; GND: ROPE _ CoreName.RopeNm["GND"]; nil: ROPE _ CoreName.RopeNm["nil"]; <<>> Signal: SIGNAL = CODE; ExpandDataMuxFrameSoft: CoreFrame.ExpandProc = { -- frameCT nil: ROPE _ CoreName.RopeNm["nil"]; data: IFUCoreData.DpCellData _ NARROW[frameCT.data]; xform: CoreXform.Xform _ CoreXform.GetXform[data.type]; domain: NAT _ CoreXform.XformSize[xform]; rowPub: CoreWire.CWire _ [frameCT.public]; rowPwr: CoreWire.CWire _ rowPub.f["pwr"]; rowIn: CoreWire.CWire _ rowPub.f["in"]; rowOut: CoreWire.CWire _ rowPub.f["out"]; rowLeft: CoreWire.CWire _ rowPub.f["left"]; rowRight: CoreWire.CWire _ rowPub.f["right"]; rowTop: CoreWire.CWire _ rowPub.f["top"]; rowBot: CoreWire.CWire _ rowPub.f["bot"]; rowCtl: CoreWire.CWire _ IF rowLeft.w.size#0 THEN rowLeft ELSE rowRight; frame: REF CoreFrame.FrameRec _ NEW[CoreFrame.FrameRec _ [first: left]]; frame.seq _ NEW[CoreFrame.FrameSeq[domain]]; FOR ii: INT DECREASING IN [0..domain) DO bitPub: Core.Wires _ NIL; blank: BOOL _ rowOut.i[0].x[ii].n[]=nil; mux: Core.CellType _ NIL; instances: CoreClasses.CellInstances _ NIL; ctx: CoreName.Context _ CoreName.NewContext[]; out: CoreWire.CWire _ rowOut.i[0].x[ii]; FOR index: INT IN [0..rowPwr.w.size) DO bitPub _ CONS[ CoreName.CtxCopyWire[ctx, rowPwr.i[index].w], bitPub]; ENDLOOP; IF NOT blank THEN { bitPub _ CONS[ CoreName.CtxCopyWire[ctx, out.w], bitPub]; FOR index: INT IN [0..rowCtl.w.size) DO ctl: CoreWire.CWire _ rowCtl.i[index].x[ii]; in: CoreWire.CWire _ rowIn.i[index].x[ii]; instance: CoreClasses.CellInstance _ CoreCreate.Instance[ CoreCreate.Transistor[ ], ["gate", ctl.w ], ["ch1", in.w ], ["ch2", out.w ] ]; instances _ CONS[ instance, instances]; bitPub _ CONS[ CoreName.CtxCopyWire[ctx, ctl.w], bitPub]; bitPub _ CONS[ CoreName.CtxCopyWire[ctx, in.w], bitPub]; ENDLOOP }; mux _ CoreCreate.Cell[ public: CoreOps.CreateWire[bitPub], onlyInternal: NIL, instances: instances, name: NIL, props: NIL]; frame.seq[ii] _ CoreFrame.NewFrameCell[0, NIL, [first: left, cell: mux]]; ctx _ CoreName.KillContext[ctx]; ENDLOOP; frameCT.class _ CoreFrame.frameCellClass; frameCT.data _ frame; CoreFrame.SetFrameExpandProc[soft, frameCT, NIL]}; ExpandDataMuxFrameHard: CoreFrame.ExpandProc = { -- frameCT data: IFUCoreData.DpCellData _ NARROW[frameCT.data]; xform: CoreXform.Xform _ CoreXform.GetXform[data.type]; domain: NAT _ CoreXform.XformSize[xform]; rowPub: CoreWire.CWire _ [frameCT.public]; rowPwr: CoreWire.CWire _ rowPub.f["pwr"]; rowIn: CoreWire.CWire _ rowPub.f["in"]; rowOut: CoreWire.CWire _ rowPub.f["out"]; rowLeft: CoreWire.CWire _ rowPub.f["left"]; rowRight: CoreWire.CWire _ rowPub.f["right"]; rowTop: CoreWire.CWire _ rowPub.f["top"]; rowBot: CoreWire.CWire _ rowPub.f["bot"]; rowCtl: CoreWire.CWire _ IF rowLeft.w.size#0 THEN rowLeft ELSE rowRight; frame: REF CoreFrame.FrameRec _ NEW[CoreFrame.FrameRec _ [first: left]]; frame.seq _ NEW[CoreFrame.FrameSeq[domain]]; FOR ii: INT DECREASING IN [0..domain) DO renameProc: CoreInstCell.RenameProc ~ {new _ code.Decode[letter: old]; IF new=NIL THEN Signal[]; RETURN[new]}; mux: Core.CellType; code: IFUCoreData.NameLetterCode _ IFUCoreData.CreateNameLetterCode ["Mux", LIST[rowTop, rowCtl, rowIn, rowOut, rowBot], ii]; generic: Core.CellType _ CoreLibrary.Get[IFUCoreCells.library, code.name]; IF generic=NIL THEN { GenList: PROC[cwire: CoreWire.CWire] RETURNS[list: LIST OF ROPE ] = { FOR index: INT DECREASING IN [0..cwire.w.size) DO letter: ROPE _ NIL; name: ROPE _ cwire.i[index].x[ii].n; IF name#NIL THEN letter _ code.Encode[name]; list _ CONS[letter, list] ENDLOOP}; obj: CD.Object _ Mux[ channels: data.channels, top: GenList[rowTop ], ctl: GenList[rowCtl ], in: GenList[rowIn ], out: GenList[rowOut ], bot: GenList[rowBot ] ]; generic _ CoreLibrary.ObjCell[obj, code.name]; CoreLibrary.Set[IFUCoreCells.library, code.name, generic]}; mux _ CoreInstCell.SpecificGeneric[generic, renameProc]; frame.seq[ii] _ CoreFrame.NewFrameCell[0, NIL, [first: left, cell: mux]]; ENDLOOP; frameCT.class _ CoreFrame.frameCellClass; frameCT.data _ frame; frame.cell _ CoreFrame.RecastFrameHard[frameCT]; IFUCoreData.BlockSides[frame.cell, [frameCT.public]]; frame.seq _ NEW[CoreFrame.FrameSeq[0]]; -- free the children CoreFrame.SetFrameExpandProc[hard, frameCT, NIL]}; textScale: INT _ 2; font: CDTexts.CDFont _ CDTexts.MakeFont["Xerox/TiogaFonts/Helvetica7", textScale]; dwText: CD.Object _ CDTexts.Create["driveWeak", font]; Mux: PROC [ channels: INT, top: LIST OF ROPE, ctl: LIST OF ROPE, in: LIST OF ROPE, out: LIST OF ROPE, bot: LIST OF ROPE] RETURNS [cell: CD.Object] = { xstrLgth: INT _ 8*lambda; xstrWth: INT _ (4+4)*lambda; tranBiasx: INT _ (xstrWth-metW)/2; xstrHt: INT _ xstrLgth + 2*difW; pFrng: INT _ (pwrW-metW)/2; topExtra: INT _ cnctSize/2 + topTail; botExtra: INT _ cnctSize/2 + botTail; pitch: CD.Position = [metPitch, met2Pitch]; muxEvenDn: BOOL = TRUE; range: CD.Position; outN: ROPE _ IF out=NIL THEN NIL ELSE out.first; iRect: CD.Rect; vdd: INT _ channels+1; gnd: INT _ channels; cellWidth: INT _ IFUCoreData.CellWidth[channels]; cnctBiasx: INT _ (cnctSize-metW)/2; outIndex, outIndexBot: INT; top _ FixGVCharInList[channels, top]; bot _ FixGVCharInList[channels, bot]; range _ [MAX[Lists.ListLength[top],Lists.ListLength[bot]], Lists.ListLength[ctl]]; outIndex _ Lists.ListItemIndexMin[top, outN]; outIndexBot _ Lists.ListItemIndexMin[bot, outN]; IF outIndex # Lists.ListItemIndexMax[top, outN] OR outIndexBot # Lists.ListItemIndexMax[bot, outN] OR (outIndex#-1 AND outIndexBot#-1 AND outIndex#outIndexBot) THEN { log.PutF["Multiple column output %g- ABORT", IO.rope[outN]]; Signal[]}; IF outIndex = -1 THEN outIndex _ outIndexBot; log.PutRope["."]; <> cell _ CDCells.CreateEmptyCell[]; IF outN#NIL AND Lists.ListItemIndexMax[top, outN]=-1 AND Lists.ListItemIndexMax[bot, outN]=-1 THEN { log.PutF["\n Output signal (%g) is not in either top or bot lists - ABORT", IO.rope[outN]]; Signal[]}; IF outN#NIL AND Lists.ListItemIndexMax[in, outN]#-1 THEN{ log.PutF["\n Output signal (%g) is also used as input - ABORT", IO.rope[outN]]; Signal[]}; FOR i: INT IN [0..range.x) DO loc: CD.Position _ [i*pitch.x, 0]; tIO: ROPE _ Lists.ListIndexItem[top, i]; bIO: ROPE _ Lists.ListIndexItem[bot, i]; topOut: BOOL _ Rope.Equal[tIO,outN]; botOut: BOOL _ Rope.Equal[bIO,outN]; tY: INT _ IF topOut THEN Lists.ListNonNILIndexMin[in] ELSE Lists.ListItemIndexMin[in,tIO]; bY: INT _ IF botOut THEN Lists.ListNonNILIndexMax[in] ELSE Lists.ListItemIndexMax[in,bIO]; 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 ~Rope.Equal[tIO, bIO] AND tY<=bY AND tIO#NIL AND bIO#NIL THEN { log.PutF["\n 2 signals (%g, %g) in same channel - ABORT", IO.rope[tIO], IO.rope[bIO]]; Signal[]}; IF tIO#NIL THEN CCDUtils.AddRet[cell:cell, level: cmosMet, size: [metW, (range.y-tY) * pitch.y + topExtra ], loc: [i*pitch.x, tY * pitch.y ]]; IF bIO#NIL THEN CCDUtils.AddRet[cell:cell, level: cmosMet, size: [metW, bY * pitch.y + botExtra ], loc: [i*pitch.x, 0 * pitch.y - botExtra ]]; ENDLOOP; FOR vgIndex: INT IN [gnd..vdd] DO CCDUtils.AddRet[cell: cell, level: cmosMet, size: [pwrW, range.y * pitch.y + topExtra + botExtra ], loc: [vgIndex*pitch.x-pFrng, - botExtra ]] ENDLOOP; AddMetalPins [cell, top, bot, 0, range.y*pitch.y+ topExtra, - botExtra, TRUE]; BEGIN xstr: CD.Object _ TransistorObject[size: [xstrWth, xstrLgth], difLayer: cmosNDif]; dcon: CD.Object _ Contact[cmosNDif]; pcon: CD.Object _ Contact[cmosPoly]; vcon: CD.Object _ Contact[cmosMet2]; scon: CD.Object _ Contact[cmosPWCont]; pvconn: CD.Object _ CDRects.CreateRect[[2*cnctSize, cnctSize], cmosMet]; 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] = {[] _ IncludeInCell[cell, object, location]}; 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] = { inst0, inst1: CD.Instance; <> 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, polW], cmosPoly]; dif: CD.Object _ CDRects.CreateRect[[dWL, difW], cmosNDif]; <> 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 -polW/2 ]]; Include[dif, [minX *pitch.x -cnctBiasx, yloc +dir*pitch.y/2 -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 ]]; inst0 _ IncludeInCell[cell, xstr, [index.x *pitch.x -tranBiasx, yloc -xstrLgth/2 ]]; inst1 _ IncludeInCell[cell, dwText, [index.x *pitch.x -tranBiasx, yloc -lambda*textScale/2 ]]; CDSatellites.Associate[inst0, inst1]}; cName: ROPE _ Lists.ListIndexItem[ctl, ctlIndex]; size: CD.Position _ [cellWidth, met2W]; loc: CD.Position _ [metW/2-leftTail, ctlIndex*pitch.y+pitch.y/2-met2W/2]; ioIndex: INT _ -1; CCDUtils.AddRet[cell:cell, size:size, loc:loc, level: cmosMet2]; CCDUtils.PutPin [cell, [met2W, met2W], loc, cmosMet2, cName]; CCDUtils.PutPin [cell, [met2W, met2W], [metW/2-leftTail+cellWidth-met2W, loc.y], cmosMet2, cName]; IF outN#NIL THEN { ioItem: ROPE _ Lists.ListIndexItem[in, ctlIndex]; IF ioItem # NIL THEN { IF ioIndex < 0 THEN ioIndex _ Lists.ListItemIndexMax[top, ioItem]; IF ioIndex < 0 THEN ioIndex _ Lists.ListItemIndexMax[bot, ioItem]; IF ioIndex >=0 THEN AddMux[index: [ioIndex, ctlIndex]]}; thsIONotGnd _ ioIndex # gnd; thsGndClear _ thsIONotGnd AND ((ioIndex NIL, ENDCASE => item; IF item=NIL AND NOT nonNilItemAdded THEN LOOP; nonNilItemAdded _ TRUE; new _ CONS[item, new] ENDLOOP}; AddGVCharToList: PROC [chans: INT, list: LIST OF ROPE] RETURNS[new: LIST OF ROPE] = { FOR ii: INT DECREASING IN [0..MAX[chans+2, Lists.ListLength[list]]) DO item: ROPE _ Lists.ListIndexItem[list, ii]; IF ii=chans+1 THEN item _ plus; IF ii=chans THEN item _ minus; new _ CONS[item, new] ENDLOOP}; plus: ROPE _ CoreName.RopeNm["+"]; minus: ROPE _ CoreName.RopeNm["-"]; log: IO.STREAM _ CoreFrame.GetLog[]; IFUCoreData.RegisterSubClassExpand [soft, "Mux", ExpandDataMuxFrameSoft]; IFUCoreData.RegisterSubClassExpand [hard, "Mux", ExpandDataMuxFrameHard]; END.