<> <> <> <> <<>> <<>> DIRECTORY Basics, CD, CDCells USING [CreateEmptyCell], CDDirectory, CDRects USING [CreateRect], CMos, CMosContacts, CMosTransistors, IFUPW, PW, PWBasics, Rope; Latch: CEDAR PROGRAM IMPORTS CDCells, CDRects, CMosContacts, CMosTransistors, CMos, IFUPW, PW, PWBasics, Rope EXPORTS IFUPW = BEGIN OPEN IFUPW; rngByte: INT = 4; rngBit: INT = 8; ioRestRef: List _ LIST["VDD", "GND"]; <<>> IFULatchRow: PUBLIC PROC [ -- Assumes byte interleaving (rngBit cells of rngByte bits) design: CD.Design, ctlNames: List, ctlSelects: LIST OF REF, enable: PW.ROPE, ioTop: LIST OF REF, output: LIST OF REF, ioBot: LIST OF REF, sequential: BOOL _ FALSE ] RETURNS [cell: PW.ObjName] = { <> <> <> <> cells: LIST OF PW.ObjName; FOR ii: INT DECREASING IN [0..rngByte*rngBit) DO index: INT _ IF sequential THEN ii MOD rngBit ELSE ii / rngByte; byte: INT _ IF sequential THEN ii / rngBit ELSE ii MOD rngByte; cells _ CONS[ MuxLatch[ design: design, ctlNames: ctlNames, ctlSelects: ExpandList[byte, index, ctlSelects, ioRestRef], enable: enable, ioTop: ExpandList[byte, index, ioTop, ioRestRef], output: ExpandList[byte, index, output, ioRestRef], ioBot: ExpandList[byte, index, ioBot, ioRestRef]], cells]; ENDLOOP; RETURN[PW.AbutListX[cells]]}; <> <<"GND" and "VDD".>> <> <> <> <> <> <> MuxLatch: PROC [ design: CD.Design, ctlNames: List, ctlSelects: List, enable: PW.ROPE, ioTop: List, output: List, ioBot: List] RETURNS [PW.ObjName] = { AddMux: PROC [index: Location] = { patch: CD.ObPtr _ CDRects.CreateRect[[8,8], CMos.ndif]; dif: CD.ObPtr _ CDRects.CreateRect[[(range.x+ioRestLength-index.x)*pitch.x,8], CMos.ndif]; xstr: CD.ObPtr _ CMosTransistors.CreateTransistor[w: 8, l: 4, difLev: CMos.ndif]; ctct: CD.ObPtr _ CMosContacts.CreateDifCon[l: 8, difLev: CMos.ndif]; half: INT _ IF (index.y MOD 2)=0 THEN pitch.y/2 ELSE -pitch.y/2; loc: Location _ [index.x*pitch.x, (mIBias+index.y)*pitch.y-2]; IF range.y=1 -- noMux Latch THEN [] _ PWBasics.IncludeApplication[cell, patch, [loc.x, loc.y]] ELSE [] _ PWBasics.IncludeApplication[cell, xstr, [loc.x-4, loc.y-2]]; [] _ PWBasics.IncludeApplication[cell, dif, [loc.x, loc.y+half]]; [] _ PWBasics.IncludeApplication[cell, ctct, [loc.x, loc.y-half]] }; <> pitch: Size = [mPitch, pBigPitch]; mIBias: INT = 5; oIBias: INT = 2; topTail: INT = 4; botTail: INT = 2; -- Need tails to prevend pins from appearing on two sides cell: CD.ObPtr _ CDCells.CreateEmptyCell[]; range: Size _ [MAX[ListLength[ioTop],ListLength[ioBot]], ListLength[ctlNames]+mIBias]; ioRest: List _ ioRestRef; ioRestLength: CARDINAL _ ListLength[ioRest]; noMux: BOOL _ range.y=1; noIORest: BOOL _ FALSE; blank: BOOL _ ctlSelects=NIL OR ListAllNil[ctlSelects]; FOR ioRest _ ioRest, ioRest.rest WHILE ioRest#NIL DO -- are VDD or GND used IF ListItemIndexMax[ctlSelects, ioRest.first]#-1 THEN EXIT ENDLOOP; IF ioRest#NIL THEN ioRest _ ioRestRef -- at least one is used so do regular case ELSE noIORest _ TRUE; IF noIORest THEN {ioRest _ NIL; ioRestLength_0}; -- noMux/noIORest latch <<>> <> FOR i: INT IN [0..range.x) DO size: Size _ [6, 0]; loc: Location _ [i*pitch.x, 0]; tIO: PW.ROPE _ ListIndexItem[ioTop, i]; bIO: PW.ROPE _ ListIndexItem[ioBot, i]; bY: INT _ ListItemIndexMax[ctlSelects, bIO]; tY: INT _ ListItemIndexMin[ctlSelects, tIO]; bY _ IF bY#-1 THEN bY+mIBias ELSE IF ListItemIndexMax[output, bIO]#-1 THEN oIBias ELSE -1; tY _ IF ListItemIndexMin[output, tIO]#-1 THEN oIBias ELSE IF tY#-1 THEN tY+mIBias ELSE range.y+mIBias; IF tY >=mIBias THEN tY _ (tY -((tY +1-mIBias) MOD 2)); IF bY >=mIBias THEN bY _ (bY -((bY +1-mIBias) MOD 2)); IF Rope.Equal[tIO, bIO] THEN tY_bY_0 ELSE IF tY<=bY THEN ERROR; size.y _ (range.y-tY) *pitch.y - pitch.y/2 + topTail; loc.y _ tY *pitch.y+6; IF tIO#NIL THEN AddRet[cell:cell, size:size, loc:loc, level: CMos.met]; size.y _ bY *pitch.y+6 + botTail; loc.y _ - botTail; IF bIO#NIL THEN AddRet[cell:cell, size:size, loc:loc, level: CMos.met]; ENDLOOP; <> IF NOT(noIORest OR blank) THEN FOR ix: INT IN [0..ioRestLength) DO bY: INT _ ListItemIndexMax[ctlSelects, ListIndexItem[ioRest, ix]]; IF bY=-1 THEN LOOP; AddRet[ cell: cell, level: CMos.met, loc: [(range.x+ix) * pitch.x, mIBias * pitch.y - 2], size: [8, (bY+(bY MOD 2)) * pitch.y - pitch.y/2 + topTail]]; ENDLOOP; <> IF NOT(noMux OR blank) THEN { bY: INT _ range.y-mIBias-1; AddRet[ cell: cell, level: CMos.met, loc: [(range.x+ioRestLength) * pitch.x, (mIBias+1) * pitch.y-2], size: [8, (bY-(bY MOD 2)) * pitch.y]]}; <> FOR i: INT IN [0..range.x) DO tName: PW.ROPE _ ListIndexItem[ioTop, i]; bName: PW.ROPE _ ListIndexItem[ioBot, i]; size: Size _ [6, 6]; loc: Location _ [i*pitch.x, range.y*pitch.y-2+topTail-size.y]; IF tName #NIL THEN PutPin [cell, size, loc, CMos.met, tName]; IF bName #NIL THEN PutPin [cell, size, [loc.x, -botTail], CMos.met, bName]; ENDLOOP; <> AddRet[cell:cell, size:[cellWidth, 8], loc:[-leftTail, 70], level: CMos.met2]; AddRet[cell:cell, size:[cellWidth,18], loc:[-leftTail, 42], level: CMos.met2]; AddRet[cell:cell, size:[cellWidth,20], loc:[-leftTail, 0], level: CMos.met2]; AddRet[cell:cell, size:[cellWidth, 4], loc:[-leftTail, 0], level: CMos.pol]; <> PutPin [cell, [4, 8], [-leftTail, 70], CMos.met2, "VBB"]; PutPin [cell, [4, 8], [cellWidth-leftTail-4, 70], CMos.met2, "VBB"]; PutPin [cell, [4,18], [-leftTail, 42], CMos.met2, "VDD"]; PutPin [cell, [4,18], [cellWidth-leftTail-4, 42], CMos.met2, "VDD"]; PutPin [cell, [4,20], [-leftTail, 0], CMos.met2, "GND"]; PutPin [cell, [4,20], [cellWidth-leftTail-4, 0], CMos.met2, "GND"]; PutPin [cell, [4, 4], [-leftTail, 0], CMos.pol, enable]; PutPin [cell, [4, 4], [cellWidth-leftTail-4, 0], CMos.pol, enable]; <> FOR i: INT IN [0..range.y-mIBias) DO cName: PW.ROPE _ ListIndexItem[ctlNames, i]; ctct: CD.ObPtr _ CMosContacts.CreateDifCon[l: 8, difLev: CMos.ndif]; size: Size _ [cellWidth, 4]; loc: Location _ [-leftTail, (mIBias+i)*pitch.y ]; IF NOT blank AND (i MOD 2)=0 THEN [] _ PWBasics.IncludeApplication [cell, ctct, [(range.x+ioRestLength)*pitch.x, loc.y+6]]; IF noMux THEN EXIT; -- noMux latch AddRet[cell:cell, size:size, loc:loc, level:CMos.pol]; <> IF cName #NIL THEN { PutPin [cell, [4, 4], loc, CMos.pol, cName]; PutPin [cell, [4, 4], [cellWidth-leftTail-4, loc.y], CMos.pol, cName]}; ENDLOOP; <> FOR ctlIndex: INT IN [0..range.y-mIBias) DO ioIndex: INT _ -1; ioItem: PW.ROPE _ ListIndexItem[ctlSelects, ctlIndex]; IF ioItem = NIL THEN LOOP; IF ioIndex < 0 THEN ioIndex _ ListItemIndexMax[ioTop, ioItem]; IF ioIndex < 0 THEN ioIndex _ ListItemIndexMax[ioBot, ioItem]; IF ioIndex < 0 THEN { ioIndex _ ListItemIndexMax[ioRest, ioItem]; IF ioIndex < 0 THEN LOOP; ioIndex _ ioIndex+range.x}; AddMux[index: [ioIndex, ctlIndex]]; ENDLOOP; <> IF NOT blank THEN FOR i: INT IN [0..range.x) DO IF ListItemIndexMax[output, ListIndexItem[ioTop, i]]#-1 OR ListItemIndexMax[output, ListIndexItem[ioBot, i]]#-1 THEN { loc: Location _ [i*pitch.x, oIBias*pitch.y+4]; size: Size _ [(range.x-i+(IF noIORest THEN 0 ELSE 1))*pitch.x, 4]; [] _ PWBasics.IncludeApplication[cell, CMosContacts.CreatePolyCon[l: 8], loc]; AddRet[cell:cell, size:size, loc:[loc.x, loc.y+2], level:CMos.pol]}; ENDLOOP; <> IF NOT blank THEN [] _ PWBasics.IncludeApplication[ cell: cell, subcell: PWBasics.ObjFromName[design, (IF noIORest THEN "SimLatch" ELSE "MuxLatch")], location: [range.x*pitch.x, 0]]; PWBasics.RepositionCell[design, cell]; RETURN[PWBasics.NameFromObj[cell]]}; IFUTriDriverRow: PUBLIC PROC [ -- Assumes byte interleaving (rngBit cells of rngByte bits) design: CD.Design, ioTop: LIST OF REF, inSelect: LIST OF REF, -- exactly one element enable: PW.ROPE, disable: PW.ROPE, outSelect: LIST OF REF, ioBot: LIST OF REF, sequential: BOOL _ FALSE ] RETURNS [cell: PW.ObjName] = { <> <> <> <> cells: LIST OF PW.ObjName; FOR ii: INT DECREASING IN [0..rngByte*rngBit) DO index: INT _ IF sequential THEN ii MOD rngBit ELSE ii / rngByte; byte: INT _ IF sequential THEN ii / rngBit ELSE ii MOD rngByte; cells _ CONS[ TriDriver[ design: design, ioTop: ExpandList[byte, index, ioTop, ioRestRef], inSelect: ExpandList[byte, index, inSelect, ioRestRef], enable: enable, disable: disable, outSelect: ExpandList[byte, index, outSelect], ioBot: ExpandList[byte, index, ioBot, ioRestRef]], cells]; ENDLOOP; RETURN[PW.AbutListX[cells]]}; TriDriver: PROC [ design: CD.Design, ioTop: List, inSelect: List, enable: PW.ROPE, disable: PW.ROPE, outSelect: List, ioBot: List ] RETURNS [PW.ObjName] = { <> topTail: INT = 8; botTail: INT = 2; pitch: Size = [mPitch, pBigPitch]; cell: CD.ObPtr _ CDCells.CreateEmptyCell[]; rangeX: INT _ MAX[ListLength[ioTop],ListLength[ioBot]]; blank: BOOL _ inSelect=NIL OR inSelect.first=NIL; gnd: BOOL _ Rope.Compare["GND", inSelect.first]=equal; vdd: BOOL _ Rope.Compare["VDD", inSelect.first]=equal; <> FOR i: INT IN [0..rangeX) DO Add: PROC[bindex, tindex, toptail, bottail: INT] = { loc.y _ bindex*pitch.y - bottail; size.y _ (tindex-bindex)*pitch.y + toptail + bottail; IF size.y>0 THEN AddRet[cell:cell, size:size, loc:loc, level: CMos.met]}; size: Size _ [6, 0]; loc: Location _ [i*pitch.x, 0]; tIO: PW.ROPE _ ListIndexItem[ioTop, i]; bIO: PW.ROPE _ ListIndexItem[ioBot, i]; tIn: BOOL _ ListItemIndexMax[inSelect, tIO]#-1; bIn: BOOL _ ListItemIndexMax[inSelect, bIO]#-1; tOut: BOOL _ ListItemIndexMax[outSelect, tIO]#-1; bOut: BOOL _ ListItemIndexMax[outSelect, bIO]#-1; IF tIO#NIL THEN SELECT TRUE FROM Rope.Equal[tIO, bIO] => {Add[0, 4, topTail, botTail]}; tOut => {Add[1, 4, topTail, 0]}; tIn => {Add[3, 4, topTail, 0]; IF bIn THEN ERROR} ENDCASE => ERROR; -- top not connected anywhere ABORT; IF bIO#NIL THEN SELECT TRUE FROM Rope.Equal[bIO, tIO] => LOOP; bIn => {Add[0, 3, 0, botTail]}; bOut => {Add[0, 1, 0, botTail]}; ENDCASE => ERROR; -- bottom not connected anywhere ABORT ENDLOOP; <> FOR i: INT IN [0..rangeX) DO tName: PW.ROPE _ ListIndexItem[ioTop, i]; bName: PW.ROPE _ ListIndexItem[ioBot, i]; size: Size _ [6, 6]; loc: Location _ [i*pitch.x, 4*pitch.y+topTail-size.y]; IF tName #NIL THEN PutPin [cell, size, loc, CMos.met, tName]; IF bName #NIL THEN PutPin [cell, size, [loc.x, -botTail], CMos.met, bName]; ENDLOOP; <> AddRet[cell:cell, size:[cellWidth, 4], loc:[-leftTail, 64], level: CMos.pol]; AddRet[cell:cell, size:[cellWidth,16], loc:[-leftTail, 48], level: CMos.met2]; AddRet[cell:cell, size:[cellWidth,16], loc:[-leftTail, 12], level: CMos.met2]; AddRet[cell:cell, size:[cellWidth, 4], loc:[-leftTail, 0], level: CMos.pol]; <> PutPin [cell, [4, 4], [-leftTail, 64], CMos.pol, enable]; PutPin [cell, [4, 4], [cellWidth-leftTail-4, 64], CMos.pol, enable]; PutPin [cell, [4,16], [-leftTail, 48], CMos.met2, "VDD"]; PutPin [cell, [4,16], [cellWidth-leftTail-4, 48], CMos.met2, "VDD"]; PutPin [cell, [4,16], [-leftTail, 12], CMos.met2, "GND"]; PutPin [cell, [4,16], [cellWidth-leftTail-4, 12], CMos.met2, "GND"]; PutPin [cell, [4, 4], [-leftTail, 0], CMos.pol, disable]; PutPin [cell, [4, 4], [cellWidth-leftTail-4, 0], CMos.pol, disable]; <> IF NOT (blank OR vdd OR gnd) THEN FOR i: INT IN [0..rangeX) DO IF ListItemIndexMin[inSelect, ListIndexItem[ioTop, i]]#-1 OR ListItemIndexMax[inSelect, ListIndexItem[ioBot, i]]#-1 THEN { loc: Location _ [ i * pitch.x, 3*pitch.y]; size: Size _ [(rangeX-i) * pitch.x, 4]; [] _ PWBasics.IncludeApplication [cell, CMosContacts.CreatePolyCon[l: 8], [loc.x, loc.y-2]]; AddRet[cell:cell, size:size, loc:loc, level:CMos.pol]}; ENDLOOP; <> IF NOT blank THEN FOR i: INT IN [0..rangeX) DO IF ListItemIndexMin[outSelect, ListIndexItem[ioTop, i]]#-1 OR ListItemIndexMax[outSelect, ListIndexItem[ioBot, i]]#-1 THEN { loc: Location _ [ i * pitch.x, 1*pitch.y]; size: Size _ [(rangeX-i) * pitch.x, 4]; [] _ PWBasics.IncludeApplication [cell, CMosContacts.CreatePolyCon[l: 8], [loc.x, loc.y-2]]; AddRet[cell:cell, size:size, loc:loc, level:CMos.pol]}; ENDLOOP; <> IF NOT blank THEN [] _ PWBasics.IncludeApplication[ cell: cell, subcell: PWBasics.ObjFromName[design, (SELECT TRUE FROM gnd => "TriStateGND", vdd => "TriStateVDD", ENDCASE => "TriStateDriver")], location: [rangeX*pitch.x, 0]]; PWBasics.RepositionCell[design, cell]; RETURN[PWBasics.NameFromObj[cell]]}; <<>> TDrive: PW.UserProc = { RETURN[ TriDriver[ design: design, ioTop: LIST["XB", "Alpa", "Beta", "Pass", "In"], inSelect: LIST["In"], enable: "PhB", disable: "PhB'", outSelect: LIST["XB"], ioBot: LIST["XB", "Alpa", "Beta", "Pass"]] ]}; MuxLatch6x6x6: PW.UserProc = { RETURN[ MuxLatch[ design: design, ctlNames: LIST["Reset", "Hold", "Set", "ASel", "Adv", "RdXBus"], ctlSelects: LIST["GND", "Last", "VDD", "Alpa", "In", "XB"], enable: "PhB", ioTop: LIST["XB", "Alpa", "Beta", "Pass", "Out", "In"], output: LIST["Out"], ioBot: LIST["XB", "Alpa", "Beta", "Pass", "Out", "Last"]] ]}; MuxLatch6x7x6: PW.UserProc = { RETURN[ MuxLatch[ design: design, ctlNames: LIST["Reset", "Hold", "Set", "BSel", "ASel", "Adv", "RdXBus"], ctlSelects: LIST["GND", "Last", "VDD", "Beta", "Alpa", "In", "XB"], enable: "PhB", ioTop: LIST["XB", "Alpa", "Beta", "Pass", "Out", "In"], output: LIST["Out"], ioBot: LIST["XB", "Alpa", "Beta", "Pass", "Out", "Last"]] ]}; Latch6x6: PW.UserProc = { RETURN[ MuxLatch[ design: design, ctlNames: LIST["Reset", "Hold", "Set", "BSel", "ASel", "Adv", "RdXBus"], ctlSelects: LIST["In"], -- one ctlSelect => plain latch enable: "PhB", ioTop: LIST["XB", "Alpa", "Beta", "Pass", "In", "Out2"], output: LIST["Out", "Out2"], ioBot: LIST["XB", "Alpa", "Beta", "Pass", "Out", "Out2"]] ]}; Blank: PW.UserProc = { RETURN[ MuxLatch[ design: design, ctlNames: LIST["Reset", "Hold", "Set", "BSel", "ASel", "Adv", "RdXBus"], ctlSelects: NIL, -- => no Latch => output = NIL enable: "PhB", ioTop: LIST["XB", "Alpa", "Beta"], output: NIL, ioBot: LIST["XB", "Alpa", "Beta"]] ]}; IFULatchRowTest: PW.UserProc = { RETURN[ IFULatchRow[ design: design, enable: "PhB", ctlNames: LIST["Reset", "Set", "Hold", "Adv", "RdXBus", "ASel", "BSel"], ctlSelects: LIST["GND", "VDD", "PCPipe2AB.#", "PCPipe1AB.#", "XB.#", "Alpha.3", "Beta.2"], ioTop: LIST["XB.#", "PCPipe1BA.#", "PCPipe1AB.#", "Gamma.1", "Beta.2", "Alpha.3"], output: LIST["PCPipe1BA.#"], ioBot: LIST["XB.#", "PCPipe1BA.#", "PCPipe2AB.#", "Gamma.1", "Beta.2", "Alpha.3"] ] ]}; IFULatchRows: PW.UserProc = { cell1: PW.ObjName _ IFULatchRow[ design: design, enable: "PhA", ctlNames: LIST["Reset", "Set", "Hold", "Adv", "RdXBus", "ASel", "BSel"], ctlSelects: LIST["GND", "VDD", "PCPipe1BA.#", "PCPipe0BA.#", "XB.#", "Alpha.3", "Beta.2"], ioTop: LIST["XB.#", "PCPipe0BA.#", "PCPipe1AB.#", "Gamma.1", "Beta.2", "Alpha.3"], output: LIST["PCPipe1AB.#"], ioBot: LIST["XB.#", "PCPipe1BA.#", "PCPipe1AB.#", "Gamma.1", "Beta.2", "Alpha.3"] ]; cell2: PW.ObjName _ IFULatchRow[ design: design, enable: "PhB", ctlNames: LIST["Reset", "Set", "Hold", "Adv", "RdXBus", "ASel", "BSel"], ctlSelects: LIST["GND", "VDD", "PCPipe2AB.#", "PCPipe1AB.#", "XB.#", "Alpha.3", "Beta.2"], ioTop: LIST["XB.#", "PCPipe1BA.#", "PCPipe1AB.#", "Gamma.1", "Beta.2", "Alpha.3"], output: LIST["PCPipe1BA.#"], ioBot: LIST["XB.#", "PCPipe1BA.#", "PCPipe2AB.#", "Gamma.1", "Beta.2", "Alpha.3"] ]; RETURN[PW.AbutY[cell2, cell1]]}; <<>> PW.Register[MuxLatch6x6x6, "Latch6x6x6"]; PW.Register[MuxLatch6x7x6, "Latch6x7x6"]; <> <> <> <> PW.Register[TDrive, "TDrive"]; END. <<>>