CCDUtilsImpl:
CEDAR
PROGRAM
IMPORTS CCDUtils, CD, CDCells, CDCreateLabels, CDDirectory, CDOps, CDRects, CDSimpleOps, CDSimpleRules, CDSymbolicObjects, CDViewer, CMosB, CMosBObjects, Convert, CoreBlock, CoreFrame, CoreGeometry, CoreInstCell, CoreLibrary, CoreName, CoreOps, FS, HashTable, ImagerFont, IO, PW, PWC, Real, Rope, VFonts
EXPORTS CCDUtils =
BEGIN
Signal: SIGNAL = CODE;
ROPE: TYPE = Core.ROPE;
GND: ROPE = CoreName.RopeNm["GND"];
VDD: ROPE = CoreName.RopeNm["VDD"];
plus: ROPE = CoreName.RopeNm["+"];
minus: ROPE = CoreName.RopeNm["-"];
NWMML: TYPE = PWC.NWMML;
CellType: TYPE = Core.CellType;
Side: TYPE = CoreFrame.Side;
cache: HashTable.Table ←
HashTable.Create[equal: HashTable.RopeEqual, hash: HashTable.HashRope];
Store: PROC[name: ROPE, obj: CD.Object] = {[]←HashTable.Store[cache, name, obj]};
Fetch:
PROC[name:
ROPE]
RETURNS[obj:
CD.Object] =
{RETURN[NARROW[HashTable.Fetch[cache, name].value, CD.Object]]};
SizeBlankName:
PROC[size:
CD.Position]
RETURNS[name:
ROPE] ~
{RETURN[ IO.PutFR["Blank-%g-%g", IO.int[size.x], IO.int[size.y]]]};
BlankObj:
PUBLIC
PROC[size:
CD.Position]
RETURNS[cell:
CD.Object] ~ {
minLineW: INT = 2 ;
name: ROPE ← SizeBlankName[size];
IF size.x=0 OR size.y=0 THEN RETURN[NIL];
cell ← Fetch[name];
IF cell#NIL THEN RETURN[cell];
cell ← CDCells.CreateEmptyCell[];
IF size.x
IN (0..4*minLineW)
OR size.y
IN (0..4*minLineW)
THEN [ ] ← PW.IncludeInCell[cell, CDRects.CreateRect[size, CD.commentLayer], [0, 0] ]
ELSE {
lwidth: INT ← MAX[minLineW, MIN[size.x/100, size.y/100]];
hor: CD.Object ← CDRects.CreateRect[[size.x, lwidth], CD.commentLayer];
ver: CD.Object ← CDRects.CreateRect[[lwidth, size.y], CD.commentLayer];
[ ] ← PW.IncludeInCell[cell, hor, [0, 0] ];
[ ] ← PW.IncludeInCell[cell, hor, [0, size.y-lwidth] ];
[ ] ← PW.IncludeInCell[cell, ver, [0, 0] ];
[ ] ← PW.IncludeInCell[cell, ver, [size.x-lwidth, 0] ]};
PW.RepositionCell[cell];
Store[name, cell]};
BlankCell:
PUBLIC
PROC[size:
CD.Position]
RETURNS[cell: CellType] ~ {
obj: CD.Object ← BlankObj[size];
name: ROPE ← SizeBlankName[size];
cell ← CoreLibrary.ObjCell[obj, name, NIL, 0];
cell ← CoreFrame.NewFrameCell[0, name, [cell: cell]]};
ObjName:
PUBLIC
PROC[obj:
CD.Object]
RETURNS[name:
ROPE] = {
IF obj=NIL THEN RETURN[NIL];
IF obj.specificRef=NIL THEN RETURN[NIL];
IF NOT ISTYPE[obj.specificRef, CD.CellPtr] THEN RETURN[NIL];
RETURN[NARROW[obj.specificRef, CD.CellPtr].name]};
ObjSize:
PUBLIC
PROC[obj:
CD.Object]
RETURNS[size:
CD.Position] =
{RETURN[CD.InterestSize[obj]]};
Layout:
PUBLIC
PROC[ct: Core.CellType]
RETURNS[obj:
CD.Object] = {
IF ct=NIL THEN RETURN[NIL];
SELECT ct.class
FROM
CoreInstCell.specificGenericCellClass => RETURN[Layout[ NARROW[ct.data]]];
CoreFrame.frameCellClass => RETURN[Layout[ CoreFrame.FCT[ct].cell ]];
ENDCASE => RETURN[PWC.Layout[ ct]]};
font1: Imager.Font ← VFonts.EstablishFont
[family:"Helvetica", size: 7, bold: TRUE, italic: FALSE, defaultOnFailure: FALSE];
font2: Imager.Font ← VFonts.EstablishFont
[family:"Helvetica", size: 14, bold: TRUE, italic: FALSE, defaultOnFailure: FALSE];
OrnateFrame:
PUBLIC PROC [cell: CellType, design: CD.Design←NIL]
RETURNS[picture: CD.Object] = {
recCell: CellType ← cell;
rSize: CD.Position;
loc: CD.Position;
sidesObj: ARRAY Side OF CD.Object;
refObj: CD.Object;
IF cell.class = CoreFrame.frameCellClass
THEN recCell ← CoreFrame.FCT[cell].cell
ELSE recCell ← cell;
refObj ← CCDUtils.Layout[recCell];
picture ← CDCells.CreateEmptyCell[];
rSize ← CD.InterestSize[refObj];
[ ] ← PW.IncludeInCell[picture, refObj, [0, 0]];
FOR side: Side
IN Side
DO
nwmmls: LIST OF NWMML ← SidePinList[recCell, side];
bias: INT = lambda;
orient: CD.Orientation;
size: CD.Position ← [0, 0];
IF nwmmls=NIL THEN LOOP;
sidesObj[side] ← CDCells.CreateEmptyCell[];
FOR nwmmls ← nwmmls, nwmmls.rest
WHILE nwmmls#
NIL
DO
textOb: CD.Object ← ScaledText
[nwmmls.first.name, [400*lambda,10*lambda],CD.commentLayer, design];
textOb ← CDTexts.CreateText[pins[i].name, font, layer];
org: CD.Position ← CD.ClientOrigin[textOb];
pos: CD.Position ;
size.x ← MAX[size.x, ((textOb.size.x+2*bias+lambda-1)/lambda)*lambda];
pos.x ← bias;
pos.y ←
SELECT side
FROM
left, right => nwmmls.first.min - org.y,
bottom, top => rSize.x - nwmmls.first.max - org.y,
ENDCASE => ERROR;
[ ] ← PW.IncludeInCell[sidesObj[side], textOb, pos];
ENDLOOP;
SELECT side
FROM
left, right => {size.y ← rSize.y};
top, bottom => {size.y ← rSize.x};
ENDCASE => ERROR;
SELECT side
FROM
left => {loc ← [-size.x, 0 ]; orient ← CDOrient.original};
right => {loc ← [ rSize.x, 0 ]; orient ← CDOrient.original};
top => {loc ← [ 0, rSize.y ]; orient ← CDOrient.rotate90};
bottom => {loc ← [ 0, -size.x ]; orient ← CDOrient.rotate90};
ENDCASE => ERROR;
CDCells.SetInterestRect[sidesObj[side], [0, 0, size.x, size.y]];
[ ] ← CDCells.RepositionCell[sidesObj[side], NIL];
[ ] ← PW.IncludeInCell[picture, sidesObj[side], loc, orient];
ENDLOOP;
[ ] ← CDCells.RepositionCell[picture, NIL]};
AddRet:
PUBLIC
PROC [cell:
CD.Object, size:
CD.Position, loc:
CD.Position, level:
CD.Layer] = {
IF (size.x MOD 2)=1 OR (size.y MOD 2)=1 OR size.x<0 OR size.y<0
IF size.x<0
OR size.y<0
THEN {
PW.WriteF["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;
[] ← PW.IncludeInCell[cell, CDRects.CreateRect[size, level], loc]};
Alt vertsion of PWC.sidePinList
Only metal2 left/right or metal1 top/bottom power is included
SidePinList:
PUBLIC
PROC [cellType: CellType, side: Side]
RETURNS [list: LIST OF NWMML ← NIL] = {
refCell: CellType;
thisSide: Side ← side;
EachWirePin: CoreGeometry.EachWirePinProc = {
SubstituteWireName: CoreOps.EachWirePairProc ~ {
IF actualWire#wire THEN RETURN;
wire←publicWire; name𡤌oreName.WireNm[wire].n; RETURN[FALSE, TRUE]};
name: ROPE ← CoreName.WireNm[wire].n;
IF side#thisSide THEN RETURN;
IF
NOT CoreBlock.OnSide[CoreFrame.SideSides[side], CoreBlock.GetWireSide[wire]]
THEN RETURN;
IF layer#cmosMet
AND layer#cmosMet2
THEN
SELECT name FROM GND, VDD, plus, minus => RETURN ENDCASE;
IF cellType.class=CoreInstCell.specificGenericCellClass
THEN
[ ] ← CoreOps.VisitBinding[refCell.public, cellType.public, SubstituteWireName];
IF name=NIL THEN RETURN;
list ← PWC.AddMergeNWMMLs[[name, wire, min, max, layer], list]};
IF cellType.class=CoreInstCell.specificGenericCellClass
THEN {refCell ← NARROW[cellType.data]} ELSE refCell ← cellType;
[] ← PWC.InterestRect[refCell];
[] ← CoreGeometry.
EnumerateWireSides
[PWC.extractMode.decoration, refCell, EachWirePin];
PWC.PosSortNWMMLs[list]};
ListNWMMLs:
PUBLIC
PROC[lst:
LIST
OF
NWMML, log:
IO.
STREAM] = {
list: LIST OF NWMML;
list ← lst; lst ← NIL;
FOR list ← list, list.rest
WHILE list#
NIL
DO
lst ← CONS[list.first, lst] ENDLOOP;
list ← lst;
FOR list ← list, list.rest WHILE list#NIL DO ListNWMML[list.first, log] ENDLOOP;
log.PutChar[IO.CR] };
ListNWMML:
PUBLIC
PROC[
nwmml: NWMML, log:
IO.
STREAM] = {
layerCard: CARDINAL ← LOOPHOLE[nwmml.layer];
log.PutF["\n%g\tpos: %5g\tsize: %5g\tlayer: %g",
IO.rope[nwmml.name],
IO.int[nwmml.min],
IO.int[nwmml.max-nwmml.min],
IO.rope[
SELECT nwmml.layer
FROM
cmosMet2 => "metal2",
cmosMet => "metal",
cmosPoly => "poly",
ENDCASE => Convert.RopeFromCard[layerCard] ] ]};
ListUniqueSignals:
PUBLIC PROC[first: Side, cell0, cell1: CellType, log:
REF ←
NIL] = {
Incrment:
PROC[table: HashTable.Table, id:
REF] = {
val: REF INT ← NARROW[HashTable.Fetch[table, id].value];
IF val=NIL THEN {val ← NEW[INT ← 0]; [] ← HashTable.Store[table, id, val]};
val^ ← val^ + 1};
nwmmls0: LIST OF NWMML ← SidePinList[cell0, CoreFrame.OppSide[first]];
nwmmls1: LIST OF NWMML ← SidePinList[cell1, first];
side0Nm: ROPE ← CoreFrame.SideRope[CoreFrame.OppSide[first]];
side1Nm: ROPE ← CoreFrame.SideRope[first];
out: IO.STREAM;
count: INT ← 0;
mark: REF ← NEW[INT ← 0];
table0: HashTable.Table ← HashTable.Create[ ];
table1: HashTable.Table ← HashTable.Create[ ];
IF log=
NIL
THEN out ← FS.StreamOpen["UniqueSignals.txt", $create]
ELSE
WITH log
SELECT
FROM
rope: ROPE => {out ← FS.StreamOpen[rope, $create]};
text: REF TEXT => {out ← FS.StreamOpen[Rope.FromRefText[text], $create]};
stm: IO.STREAM => {out ← stm};
ENDCASE => {Signal[]};
FOR temp:
LIST
OF
NWMML ← nwmmls0, temp.rest
WHILE temp#
NIL
DO
Incrment[table0, temp.first.name] ENDLOOP;
FOR temp:
LIST
OF
NWMML ← nwmmls1, temp.rest
WHILE temp#
NIL
DO
Incrment[table1, temp.first.name] ENDLOOP;
out.PutF["\nUnique signal log %g\n%10g side of %g\n%10g side of %g\n",
IO.time[],
IO.rope[side0Nm], IO.rope[CoreName.CellNm[cell0].n],
IO.rope[side1Nm], IO.rope[CoreName.CellNm[cell1].n] ];
FOR temp:
LIST
OF
NWMML ← nwmmls0, temp.rest
WHILE temp#
NIL
DO
val: REF INT ← NARROW[HashTable.Fetch[table0, temp.first.name].value];
IF val^<2
AND
NOT HashTable.Fetch[table1, temp.first.name].found
THEN
out.PutF["\n%g\tpos: %5g", IO.rope[temp.first.name], IO.int[temp.first.min]] ENDLOOP;
out.PutRope["\n******"];
FOR temp:
LIST
OF
NWMML ← nwmmls1, temp.rest
WHILE temp#
NIL
DO
val: REF INT ← NARROW[HashTable.Fetch[table1, temp.first.name].value];
IF val^<2
AND
NOT HashTable.Fetch[table0, temp.first.name].found
THEN
out.PutF["\n%g\tpos: %5g", IO.rope[temp.first.name], IO.int[temp.first.min]] ENDLOOP;
out.PutRope["\n"]; out.Close[]};
PutPin:
PUBLIC
PROC[cell:
CD.Object, size, loc:
CD.Position, level:
CD.Layer, name:
ROPE] = {
pinApl:
CD.Instance
← PW.IncludeInCell[cell, CDSymbolicObjects.CreatePin[size], loc];
CDSymbolicObjects.SetName[pinApl, name];
CDSymbolicObjects.SetLayer[pinApl, level]};
RenamePins: PUBLIC PROC[
object: CD.Object,
pinNameProc: CCDUtils.PinNameProc]
RETURNS[newObject: CD.Object] = {
KeepPinOnEdge: CDSymbolicObjects.InstEnumerator ~ {
newRope: ROPE;
newInst: CD.Instance;
side: Side;
side ← PWPins.GetSide[object, inst];
IF side=none THEN RETURN;
newRope ← pinNameProc[inst, side];
IF Rope.IsEmpty[newRope] THEN RETURN;
newInst ← NEW[CD.InstanceRep ← [
ob: CDSymbolicObjects.CreatePin[inst.ob.size],
location: inst.location,
orientation: inst.orientation ]];
CDProperties.CopyProps[inst.properties, newInst];
CDSymbolicObjects.SetName[newInst, newRope];
newCellPtr.contents ← CONS[newInst, newCellPtr.contents] };
newCellPtr: CD.CellPtr;
inst: CD.Instance ← NEW[CD.InstanceRep ← [ob: object]];
CDProperties.PutInstanceProp[inst, $StopEnumerateDeepPins, $StopEnumerateDeepPins];
newObject ← CDCells.CreateEmptyCell[];
newCellPtr ← NARROW[newObject.specificRef];
[] ← PWPins.EnumerateDeepPins[object, KeepPinOnEdge];
newCellPtr.contents ← CONS[inst, newCellPtr.contents];
CDCells.SetInterestRect[newObject, CD.InterestRect[object]];
RETURN[newObject] };
cmos: PUBLIC CD.Technology = CMosB.cmosB;
cmosNDif: PUBLIC CD.Layer ← CMosB.ndif;
cmosPDif: PUBLIC CD.Layer ← CMosB.pdif;
cmosWPDif: PUBLIC CD.Layer ← CMosB.wpdif;
cmosWNDif: PUBLIC CD.Layer ← CMosB.wndif;
cmosPoly: PUBLIC CD.Layer ← CMosB.pol;
cmosMet: PUBLIC CD.Layer ← CMosB.met;
cmosMet2: PUBLIC CD.Layer ← CMosB.met2;
cmosPWCont: PUBLIC CD.Layer ← CMosB.pwellCont;
cmosNWCont: PUBLIC CD.Layer ← CMosB.nwellCont;
cmosNWell: PUBLIC CD.Layer ← CMosB.nwell;
lambda: PUBLIC INT ← CMosB.lambda;
pwrW: PUBLIC INT ← 5*lambda;
metW: PUBLIC INT ← 3*lambda;
met2W: PUBLIC INT ← 4*lambda;
polW: PUBLIC INT ← 2*lambda;
difW: PUBLIC INT ← 2*lambda;
topTail: PUBLIC INT ← 2*lambda;
leftTail: PUBLIC INT ← 6*lambda; -- to center of 0th channel
rightTail: PUBLIC INT ← 2*lambda; -- metPitch-leftTail
botTail: PUBLIC INT ← 1*lambda;
cnctSize: PUBLIC INT ← 4*lambda;
metPitch: PUBLIC INT ← 8*lambda;
met2Pitch: PUBLIC INT ← 8*lambda;
polMuxPitch: PUBLIC INT ← 8*lambda;
polPitch: PUBLIC INT ← 6*lambda; -- without adjacent contacts
Contact:
PUBLIC
PROC[layer:
CD.Layer]
RETURNS[cntc:
CD.Object] = {
RETURN[
SELECT layer
FROM
cmosMet2, cmosPoly, cmosNDif, cmosPDif, cmosWPDif, cmosWNDif =>
CDSimpleRules.Contact[cmosMet, layer],
cmosPWCont, cmosNWCont =>
CMosBObjects.CreateDifCon[layer],
ENDCASE => ERROR]};
TransistorObject:
PUBLIC
PROC[size:
CD.Position, difLayer:
CD.Layer]
RETURNS[trans:
CD.Object]=
{trans ← CMosBObjects.CreateTransistor[size: size, difLayer: difLayer]};
textCache: CD.Design ← CDOps.CreateDesign[CD.FetchTechnology[$cmosB]];
ScaledText:
PUBLIC
PROC[text:
ROPE, box:
CD.Position, layer:
CD.Layer, design: CD.Design←NIL]
RETURNS[cell: CD.Object ← NIL] = {
MakeName:
PROC[fontIndex:
INT]
RETURNS[name:
ROPE] = {
name ← IO.PutFR["Label%g-%g[%g]", IO.int[fontIndex], IO.int[scaleFactor], IO.rope[text]]};
Scale:
PROC[font: Imager.Font]
RETURNS[scale:
INT] = {
extents: ImagerFont.Extents ← ImagerFont.RopeBoundingBox[font, text];
strSize: CD.Position;
IF box.x<4 OR box.y<4 THEN RETURN[0];
strSize.x ← Real.RoundI[extents.rightExtent+extents.leftExtent];
strSize.y ← Real.RoundI[extents.ascent+extents.descent];
scale ← MIN[box.x/strSize.x, box.y/strSize.y]};
scaleFactor: INT;
IF design=NIL THEN design ← textCache;
IF text.Length[]=0 THEN text ← "<no name>";
scaleFactor ← Scale[font2];
IF scaleFactor>0
THEN {
cell ← CDDirectory.Fetch[design, MakeName[2]].object;
IF cell=
NIL
THEN {
cell ← CDCreateLabels.CreateTextCell[design, text, font2, scaleFactor, layer];
[] ← CDDirectory.Include[design, cell, MakeName[2]];
RETURN[cell]} };
scaleFactor ← Scale[font1];
IF scaleFactor>0
THEN {
cell ← CDDirectory.Fetch[design, MakeName[1]].object;
IF cell=
NIL
THEN {
cell ← CDCreateLabels.CreateTextCell[design, text, font1, scaleFactor, layer];
[] ← CDDirectory.Include[design, cell, MakeName[2]];
RETURN[cell]} };
RETURN[NIL] };
ShowModule:
PUBLIC
PROC[name:
ROPE, design:
CD.Design ←
NIL] = {
frameCT: CellType;
new: BOOL ← design=NIL;
decoratedObj: CD.Object;
IF new
THEN {
design ← CDOps.CreateDesign[CD.FetchTechnology[$cmosB]];
CDSimpleOps.RenameDesign[design, name]};
frameCT ← CoreFrame.ReadFrameCache[name];
IF frameCT=NIL THEN Signal[];
IF frameCT=NIL THEN RETURN;
mainObj ← CCDUtils.Layout[frameCT];
[] ← CDDirectory.Include[design, mainObj, name];
decoratedObj ← OrnateFrame[frameCT, design];
[] ← CDDirectory.Include[design, decoratedObj, Rope.Cat["Ornate", name]];
IF new THEN CDOps.IncludeObjectI[design, decoratedObj, [0, 0]];
CDCleanUp.CleanUp[ design, NIL];
[ ] ← CDViewer.CreateViewer[design]};
DrawX:
PUBLIC
PROC[obj0, obj1, obj2, obj3, obj4:
CD.Object ←
NIL] =
{Draw[TRUE, obj0, obj1, obj2, obj3, obj4]};
DrawY:
PUBLIC
PROC[obj0, obj1, obj2, obj3, obj4:
CD.Object ←
NIL] =
{Draw[FALSE, obj0, obj1, obj2, obj3, obj4]};
Draw:
PROC[inX:
BOOL, obj0, obj1, obj2, obj3, obj4:
CD.Object ←
NIL] = {
design: CD.Design ← CDOps.CreateDesign[CD.FetchTechnology[$cmosB]];
pos: CD.Position ← [0, 0];
Add:
PROC[obj:
CD.Object, name:
ROPE] = {
[] ← CDDirectory.Include[design, obj, name];
CDOps.IncludeObjectI[design, obj, pos];
IF inX
THEN pos.x ← pos.x + ObjSize[obj].x
ELSE pos.y ← pos.y + ObjSize[obj].y};
IF obj0#NIL THEN {Add[obj0, "0"]};
IF obj1#NIL THEN {Add[obj1, "1"]};
IF obj2#NIL THEN {Add[obj2, "2"]};
IF obj3#NIL THEN {Add[obj3, "3"]};
IF obj4#NIL THEN {Add[obj4, "4"]};
[ ] ← CDViewer.CreateViewer[design] };
InsertModule: PUBLIC PROC
[cell: CellType, name: ROPE ← NIL, design: CD.Design] = {
new: BOOL ← design=NIL;
mainObj, decoratedObj: CD.Object;
name ← CoreName.CellNm[cell, name].n;
IF new THEN {
design ← CDOps.CreateDesign[CD.FetchTechnology[$cmosB]];
CDSimpleOps.RenameDesign[design, name]};
CoreFrame.Expand[hard, cell];
CoreFrame.NameFrame[cell, name];
[ ] ← CoreGlue.RouteHard[cell];
mainObj ← CoreFrame.Layout[cell];
[] ← CDDirectory.Include[design, mainObj, name];
decoratedObj ← OrnateFrame[cell, design];
[] ← CDDirectory.Include[design, decoratedObj, Rope.Cat["Ornate", name]];
IF new THEN CDOps.IncludeObjectI[design, decoratedObj, [0, 0]];
CDCleanUp.CleanUp[ design, NIL];
[ ] ← CDViewer.CreateViewer[design];
[ ] ← CDIO.WriteDesign[design, design.name] };
InsertModule: PUBLIC PROC[cell:CellType, name: ROPE ← NIL, design: CD.Design ←NIL]={
name ← CoreName.CellNm[cell, name].n;
CoreFrame.Expand[hard, cell];
CoreFrame.NameFrame[cell, name];
[ ] ← CoreGlue.RouteHard[cell];
CoreFrame.WriteFrameCheckPoint[cell]};
log: IO.STREAM ← CoreFrame.GetLog[];
IF metW # CDSimpleRules.MinWidth[cmosMet] THEN ERROR;
IF met2W # CDSimpleRules.MinWidth[cmosMet2] THEN ERROR;
IF polW # CDSimpleRules.MinWidth[cmosPoly] THEN ERROR;
IF difW # CDSimpleRules.MinWidth[cmosNDif] THEN ERROR;
END.