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] = {
ctlSelects, ioTop, output and ioBot share a common format.
IF a top level item is a rope then a byte and bit index are appended to each rope.
IF a top level item is a List of rope then a bit index is appended to each rope.
IF a top level item is a List of List of rope then each rope is used as is.
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]]};
A multiplexed latch has up to 6 vertical metal input/output wires and built-in inputs:
"GND" and "VDD".
Any number of horizontal poly control wires can be included but each can select at most one of the possible inputs.
A noMux latch is implied when only one (dummy) horizontal poly control line is specified. In this case there is space for 7 vertical metal input/output wires.
Output lines are specified by the output list.
NIL in either the top or bottom lists will preserve a space at the appropiate location.
ctlNames and ctlSelects are ordered: LIST[bottom...top].
top and bot are ordered: LIST[left...right].
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]] };
Constants
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𡤀}; -- noMux/noIORest latch
Primary Metal wires
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𡤋Y𡤀
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;
IORest metal wires
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;
Collection node metal wire
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]]};
Insert Metal Pins
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;
Enable and power Wires
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];
Insert Enable and power Pins
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];
Poly wires and latch input node contacts
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];
Insert Pins
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;
Mux connections
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;
Ouput connections
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;
Latch Cell
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] = {
ctlSelects, ioTop, output and ioBot share a common format.
IF a top level item is a rope then a byte and bit index are appended to each rope.
IF a top level item is a List of rope then a bit index is appended to each rope.
IF a top level item is a List of List of rope then each rope is used as is.
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] = {
Constants
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;
Metal wires
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;
Insert Metal Pins
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;
Enables and power Wires
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];
Insert Enable and power Pins
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];
Input connections
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;
Ouput connections
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;
Cell
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[Latch6x6, "Latch6x6"];
PW.Register[Blank, "Blank"];
PW.Register[IFULatchRowTest, "IFULatchRowTest"];
PW.Register[IFULatchRows, "IFULatchRows"];
PW.Register[TDrive, "TDrive"];
END.