IFUPWImpl.mesa
Copyright c 1985 by Xerox Corporation. All rights reserved.
Last Edited by Curry, January 27, 1986 9:42:58 am PST
DIRECTORY
CD,
CDCells,
CDExtras,
CDFrame,
CDIO,
CDOps,
CDOrient,
CDPinObjects,
CDProperties,
CDRects USING [CreateRect],
CDSequencer,
CDSil,
CDSimpleOps,
CDViewer,
Convert,
Commander,
DragOpsCross,
IFUPW,
IO,
PW,
PWPins,
Rope,
ViewerClasses;
IFUPWImpl: CEDAR PROGRAM
IMPORTS CD, CDCells, CDExtras, CDFrame, CDIO, CDOps, CDPinObjects, CDProperties, CDRects, CDSequencer, CDSil, CDSimpleOps, CDViewer, Convert, IO, IFUPW, PW, PWPins, Rope
EXPORTS IFUPW =
BEGIN OPEN IFUPW;
Error: PUBLIC ERROR[msg: ROPE] = CODE;
log: PUBLIC IO.STREAM ← CDFrame.GetLog[];
GND: PUBLIC Rope.ROPE ← "GND";
VDD: PUBLIC Rope.ROPE ← "VDD";
IFUDataColSeq: PUBLIC RowParams ← NEW[RowParamsRec ← [seq: TRUE] ];
IFUDataColNSeq: PUBLIC RowParams ← NEW[RowParamsRec ← [seq: FALSE] ];
ChangePinName: PUBLIC PROC[obj: CD.Object, oldName, newName: ROPE] = {
pins: CD.InstanceList ← CDPinObjects.FindPins[obj, oldName];
FOR pins ← pins, pins.rest WHILE pins#NIL DO
CDPinObjects.SetName[pins.first, newName] ENDLOOP };
ConnSpec: TYPE = REF ConnSeqRec;
ConnSeqRec: TYPE = RECORD[SEQUENCE size: CARDINAL OF CnntRec];
CnntRec:  TYPE = RECORD[name: Rope.ROPE, y: INT];
BuildConnSpec: PROC[in, out: List, topY, botY, refY: INT, refCell: CD.Object]
RETURNS[connSpec: ConnSpec] = {
done: BOOL     ← FALSE;
size, index: CARDINAL ← ListLength[in] + ListLength[out] + 2;
connSpec ← NEW[ConnSeqRec[size]];
connSpec[size-1].name ← NIL; connSpec[size-1].y ← topY;
connSpec[0].name  ← NIL; connSpec[0].y  ← botY;
index ← 1;
FOR ii: INT IN [0..ListLength[in]) DO
connSpec[index].name ← in.first; in ← in.rest;
connSpec[index].y  ← refY +
CDPinObjects.FindPins[refCell, IO.PutFR["In%g", IO.int[ii]]].first.location.y;
index ← index + 1 ENDLOOP;
FOR ii: INT IN [0..ListLength[out]) DO
connSpec[index].name ← out.first; out ← out.rest;
connSpec[index].y  ← refY +
CDPinObjects.FindPins[refCell, IO.PutFR["Out%g", IO.int[ii]]].first.location.y;
index ← index + 1 ENDLOOP;
WHILE NOT done DO
done ← TRUE;
FOR ii: INT IN [0..size-1) DO
ty:   INT   ← connSpec[ii].y;
tname: Rope.ROPE ← connSpec[ii].name;
IF connSpec[ii].y <= connSpec[ii+1].y THEN LOOP;
done      ← FALSE;
connSpec[ii].y   ← connSpec[ii+1].y;
connSpec[ii].name  ← connSpec[ii+1].name;
connSpec[ii+1].y  ← ty;
connSpec[ii+1].name ← tname ENDLOOP ENDLOOP };
IOConnect: PUBLIC PROC[
design: CD.Design,
cell:  CD.Object,
top:  List,
in:   List,
out:  List,
bot:  List,
refcell: CD.Object,
refX:  INT,
refY:  INT,
topY:  INT,
botY:  INT ] = {
PurgeNILLsFromList: PUBLIC PROC [list: List] RETURNS[clean: List] = {
IF list = NIL THEN RETURN[NIL];
clean ← PurgeNILLsFromList[list.rest];
IF list.first#NIL THEN clean ← CONS[list.first, clean]};
Same: PROC[idx1, idx2: CARDINAL] RETURNS[BOOL] =
{RETURN[Rope.Equal[connSpec[idx1].name, connSpec[idx2].name]]};
connSpec: ConnSpec;
tIdx, bIdx: CARDINAL ← 0;
in  ← PurgeNILLsFromList[in];
out ← PurgeNILLsFromList[out];
connSpec ← BuildConnSpec[in, out, topY, botY, refY, refcell];
tIdx ← connSpec.size-1;
bIdx ← 0;
FOR i: INT IN [0..nofVWires) DO
Add: PROC[idx1, idx2: CARDINAL] RETURNS[BOOL] = {
IF ~Same[idx1, idx2] THEN RETURN[FALSE];
loc.y ← connSpec[idx1].y;
size.y ← connSpec[idx2].y - connSpec[idx1].y;
IF size.y < 0 THEN ERROR;
AddRet[cell:cell, size: size, loc: loc, level: cmosMet];
RETURN[TRUE]};
size: Size  ← [metW, 0];
loc: Location ← [refX+i*metPitch+leftTail, 0];
connSpec[tIdx].name ← ListIndexItem[top,  i];
connSpec[bIdx].name  ← ListIndexItem[bot,  i];
IF connSpec[tIdx].name#NIL THEN FOR ii: INT IN [bIdx..tIdx) DO
IF Add[ ii, tIdx] THEN EXIT; REPEAT FINISHED => ERROR Error
[IO.PutFR["Orphan top signal: %g", IO.rope[connSpec[tIdx].name]]] ENDLOOP;
IF connSpec[bIdx].name#NIL THEN FOR ii: INT DECREASING IN (bIdx..tIdx) DO
IF Add[ bIdx, ii] THEN EXIT; REPEAT FINISHED => IF ~Same[bIdx, tIdx] THEN ERROR
Error[IO.PutFR["Orphan bottom signal: %g", IO.rope[connSpec[bIdx].name]]] ENDLOOP;
ENDLOOP;
Horizontal connections
IF ListLength[out]#0 THEN FOR i: INT IN [0..nofVWires) DO
AddCnt: PROC[idx: CARDINAL] = {
ctct, wire: CD.Object;
IF ~Same[idx, tIdx] AND ~Same[idx, bIdx] THEN RETURN;
wLoc.y ← connSpec[idx].y;
ctct ← Contact[cmosPoly];
wire ← CDRects.CreateRect[[wLen, polW], cmosPoly];
[] ← PW.IncludeInCell[cell, ctct,
[wLoc.x-(cnctSize-metW)/2, wLoc.y-(cnctSize-polW)/2]];
[] ← PW.IncludeInCell[cell, wire, wLoc] };
wLen: INT ← (nofVWires-1-i)*metPitch + cnctSize;
wLoc: Location ← [refX+i * metPitch +leftTail, 0];
connSpec[tIdx].name ← ListIndexItem[top,  i];
connSpec[bIdx].name  ← ListIndexItem[bot,  i];
FOR ii: INT IN (bIdx..tIdx) DO AddCnt[ii] ENDLOOP;
ENDLOOP };
AddMetalPins: PUBLIC PROC
[cell: CD.Object, top, bot: List, refX, topY, botY: INT, realNames: BOOL] = {
length: INTMAX[ListLength[top], ListLength[bot]];
FOR i: INT IN [0..length) DO
tName: ROPE ← ListIndexItem[top, i];
bName: ROPE ← ListIndexItem[bot, i];
size: Size  ← [metW, metW];
loc: Location ← [refX+i*metPitch+leftTail, topY-size.y];
IF tName #NIL THEN PutPin [cell, size, loc,   cmosMet,
(IF realNames THEN tName ELSE NIL)];
IF bName #NIL THEN PutPin [cell, size, [loc.x, botY], cmosMet,
(IF realNames THEN bName ELSE NIL)];
ENDLOOP };
AddRet: PUBLIC PROC [cell: CD.Object, size: Size, loc: Location, 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 ERROR Error[IO.PutFR
["Strange rectangle size [%g, %g]", IO.int[size.x], IO.int[size.y]]];
IF size.x=0 OR size.y=0 THEN RETURN;
[] ← PW.IncludeInCell[cell, CDRects.CreateRect[size, level], loc]};
PutPin: PUBLIC PROC[cell:CD.Object, size:Size, loc:Location, level:CD.Layer, name:ROPE] = {
pinApl: CD.Instance
PW.IncludeInCell[cell, CDPinObjects.CreatePinOb[size], loc];
CDPinObjects.SetName[pinApl, name];
CDPinObjects.SetLayer[pinApl, level]};
SizeOf: PUBLIC PROC[design: CD.Design, cell: CD.Object] RETURNS[size: Size] = {
RETURN[CD.InterestSize[cell ] ]};
Merge: PUBLIC PROC[design: CD.Design, side: Side, cell1, cell2: PW.ObjName]
RETURNS[cell: PW.ObjName] = {
obj: CD.Object ← CDCells.CreateEmptyCell[];
obj1: CD.Object ← PWBasics.ObjFromName[design, cell1];
obj2: CD.Object ← PWBasics.ObjFromName[design, cell2];
size1: Size ← CD.InterestSize[obj1];
size2: Size ← CD.InterestSize[obj2];
[ ] ← PW.IncludeInCell[obj, obj1, [0, 0]];
SELECT side FROM
top  => [ ] ← PW.IncludeInCell[obj, obj2, [0, size1.y-size2.y]];
bottom => [ ] ← PW.IncludeInCell[obj, obj2, [0, 0]];
right  => [ ] ← PW.IncludeInCell[obj, obj2, [0, size1.x-size2.x]];
left  => [ ] ← PW.IncludeInCell[obj, obj2, [0, 0]];
ENDCASE;
PW.IncludeInDirectory[design, obj];
cell ← PWBasics.NameFromObj[obj]};
ProcRegToList: PUBLIC PROC [reg: ProcessorReg] RETURNS[new: List] =
{val: CARDINALLOOPHOLE[reg]; RETURN[CardToList8[val]]};
CardToList8: PUBLIC PROC [val: CARDINAL] RETURNS[new: List] = {
new ← NIL;
THROUGH [0..8) DO
new ← CONS[(IF (val MOD 2)=1 THEN VDD ELSE GND), new];
val ← val/2;
ENDLOOP};
FixGVInList: PUBLIC PROC [list: List] RETURNS[new: List] =
{RETURN[AddGVToList[DelGVFromList[list]]]};
DelGVFromList: PUBLIC PROC [list: List] RETURNS[new: List] = {
nonNilItemAdded: BOOLFALSE;
IF list=NIL THEN RETURN[NIL];
FOR ii: INT DECREASING IN [0..ListLength[list]) DO
item: ROPE ← ListIndexItem[list, ii];
IF Rope.Equal[item, GND] OR Rope.Equal[item, VDD] THEN item ← NIL;
IF item=NIL AND NOT nonNilItemAdded THEN LOOP;
nonNilItemAdded ← TRUE;
new ← CONS[item, new] ENDLOOP};
AddGVToList: PUBLIC PROC [list: List] RETURNS[new: List] = {
FOR ii: INT DECREASING IN [0..MAX[nofVWires, ListLength[list]]) DO
item: ROPE ← ListIndexItem[list, ii];
IF ii=nofVWires-1 THEN item ← VDD;
IF ii=nofVWires-2 THEN item ← GND;
new ← CONS[item, new] ENDLOOP};
AddGVToLIST: PUBLIC PROC [list: LIST OF REF, indexGV: BOOL]
RETURNS[new: LIST OF REF] = {
FOR ii: INT DECREASING IN [0..MAX[nofVWires, LISTLength[list]]) DO
item: REF ← LISTIndexItem[list, ii];
IF ii=nofVWires-1 THEN item ← IF indexGV THEN VDD.Cat["."] ELSE VDD;
IF ii=nofVWires-2 THEN item ← IF indexGV THEN GND.Cat["."] ELSE GND;
new ← CONS[item, new] ENDLOOP};
ListAllNil: PUBLIC PROC [list: List] RETURNS[allNIL: BOOL] =
{FOR list ← list, list.rest WHILE list#NIL DO
IF list.first#NIL THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]};
LISTAllNil: PUBLIC PROC [list: LIST OF REF] RETURNS[allNIL: BOOL] =
{FOR list ← list, list.rest WHILE list#NIL DO
IF list.first#NIL THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]};
List4: PUBLIC PROC [r0, r1, r2, r3: ROPE] RETURNS[list: List] = {
list ← CONS[r0, CONS[r1, CONS[r2, CONS[r3, NIL]]]]};
List8: PUBLIC PROC [r0, r1, r2, r3, r4, r5, r6, r7: ROPE] RETURNS[list: List] = {
list ← CONS[r0,CONS[r1,CONS[r2,CONS[r3,CONS[r4,CONS[r5,CONS[r6,CONS[r7, NIL]]]]]]]]};
LISTn: PUBLIC PROC [r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15: REFNIL ]
RETURNS[list: LIST OF REF] = {
refs: ARRAY [0..16) OF REF ← [r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15];
index: INT;
FOR index DECREASING IN [0..16) WHILE refs[index]=NIL DO ENDLOOP;
FOR index←index, index-1 WHILE index>=0 DO
IF refs[index]#NIL AND ISTYPE[refs[index], REF TEXT]
THEN list ← CONS[Rope.FromRefText[NARROW[refs[index]]], list ]
ELSE list ← CONS[refs[index], list] ENDLOOP};
Listn: PUBLIC PROC
[r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15: ROPENIL ]
RETURNS[list: List] = {
refs: ARRAY [0..16) OF ROPE
[r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15];
index: INT;
FOR index DECREASING IN [0..16) WHILE refs[index]=NIL DO ENDLOOP;
FOR index←index, index-1 WHILE index>=0 DO list ← CONS[refs[index], list] ENDLOOP};
ListConcat: PUBLIC PROC [list1, list2: List] RETURNS[new: List] = {
FOR i: INT DECREASING IN [0..ListLength[list2]) DO
new ← CONS[ ListIndexItem[list2, i], new] ENDLOOP;
FOR i: INT DECREASING IN [0..ListLength[list1]) DO
new ← CONS[ ListIndexItem[list1, i], new] ENDLOOP};
ListLength: PUBLIC PROC [list: List] RETURNS[size: INT] =
{FOR size ← 0, size+1 WHILE list#NIL DO list←list.rest ENDLOOP};
LISTLength: PUBLIC PROC [list: LIST OF REF] RETURNS[size: INT] =
{FOR size ← 0, size+1 WHILE list#NIL DO list←list.rest ENDLOOP};
ListIndexItem: PUBLIC PROC [list: List, index: INT] RETURNS[item: ROPE] = {
FOR index ← index, index-1 WHILE index#0 AND list#NIL DO list←list.rest ENDLOOP;
RETURN[IF list=NIL THEN NIL ELSE list.first]};
LISTIndexItem: PUBLIC PROC[list: LIST OF REF, index: INT] RETURNS[item: REF] = {
FOR index ← index, index-1 WHILE index#0 AND list#NIL DO list←list.rest ENDLOOP;
RETURN[IF list=NIL THEN NIL ELSE list.first]};
ListItemIndexMin: PUBLIC PROC [list: List, item: ROPE] RETURNS[index: INT] = {
IF item=NIL THEN RETURN[-1];
FOR index ← 0, index+1 WHILE list#NIL DO
IF Rope.Equal[list.first, item] THEN RETURN[index];
list←list.rest ENDLOOP;
RETURN[-1]};
ListNonNILIndexMin: PUBLIC PROC [list: List] RETURNS[index: INT] = {
FOR index ← 0, index+1 WHILE list#NIL DO
IF list.first#NIL THEN RETURN[index];
list←list.rest ENDLOOP;
RETURN[-1]};
ListItemIndexMax: PUBLIC PROC [list: List, item: ROPE] RETURNS[index: INT] = {
count: INT ← -1;
index ← -1;
IF item=NIL THEN RETURN[-1];
FOR list ← list, list.rest WHILE list#NIL DO
count ← count+1;
IF Rope.Equal[list.first, item] THEN index ← count ENDLOOP};
ListNonNILIndexMax: PUBLIC PROC [list: List] RETURNS[index: INT] = {
count: INT ← -1;
index ← -1;
FOR list ← list, list.rest WHILE list#NIL DO
count ← count+1;
IF list.first#NIL THEN index ← count ENDLOOP};
ReverseList: PUBLIC PROC [list: List] RETURNS [new: List] =
{FOR list ← list, list.rest WHILE list#NIL DO new ← CONS[list.first, new] ENDLOOP};
ReverseLIST: PUBLIC PROC [list: LIST OF REF] RETURNS [new: LIST OF REF] =
{FOR list ← list, list.rest WHILE list#NIL DO new ← CONS[list.first, new] ENDLOOP};
AppendIndexToRope: PUBLIC PROC[index: INT, item: ROPE] -- If last char is '.
RETURNS[ROPE] = {
IF Rope.Find[item, ".", 0]=-1 THEN RETURN[item];
RETURN[Rope.Cat[item, Convert.RopeFromInt[index, 36, FALSE] ] ] };
ExpandList: PUBLIC PROC[index1, index2: INT, list: LIST OF REF]
RETURNS[new: List] ={
item1, item2, item3: ROPENIL;
IF list = NIL THEN RETURN[NIL];
new ← ExpandList[index1, index2, list.rest];
IF list.first = NIL THEN RETURN[CONS[NIL, new]];
WITH list.first SELECT FROM
first: Rope.ROPE    => item1 ← first;
first: REF TEXT    => item1 ← Rope.FromRefText[first];
first: LIST OF REF   => {
WITH LISTIndexItem[first, index1] SELECT FROM
second: Rope.ROPE    => item2 ← second;
second: REF TEXT    => item2 ← Rope.FromRefText[second];
second: LIST OF REF   => {
WITH LISTIndexItem[second, index2] SELECT FROM
third: Rope.ROPE    => item3 ← third;
third: REF TEXT    => item3 ← Rope.FromRefText[third];
third: REF     => IF third#NIL THEN ERROR;
ENDCASE      => ERROR };
second: List     => item3 ← ListIndexItem[second, index2];
second: REF     => IF second#NIL THEN ERROR;
ENDCASE      => ERROR };
first: LIST OF List   => TRUSTED {
second: List ← LOOPHOLE[LISTIndexItem[LOOPHOLE[first], index1]];
item3   ← ListIndexItem[second, index2]};
first: List      => item2 ← ListIndexItem[first, index1];
first: REF      => IF first#NIL THEN ERROR;
ENDCASE      => ERROR;
IF item1#NILTHEN item2 ← AppendIndexToRope[index1, item1];
IF item2#NILTHEN item3 ← AppendIndexToRope[index2, item2];
RETURN[CONS[item3, new] ]};
UniqueIndex: INT ← 0;
UniqueCellName: PUBLIC PROC[type: ROPE, top, bot, ins, outs: List]
RETURNS[name: ROPE] = {
Index: PROC[rope: ROPE] RETURNS[index: INT] = {
IF Rope.Equal[rope, "GND"] THEN RETURN[6];
IF Rope.Equal[rope, "VDD"] THEN RETURN[7];
index ← ListItemIndexMax[top, rope];
IF index IN [6..8) THEN ERROR Error["Impossible"];
IF index IN [0..12) THEN RETURN[index];
IF index # -1  THEN ERROR Error["Impossible"];
index ← ListItemIndexMax[bot, rope];
IF index IN [6..8) THEN ERROR Error["Impossible"];
IF index IN [0..12) THEN RETURN[index+12];
IF index = -1   THEN RETURN[31];
ERROR Error["Impossible"]};
topSig, botSig, tbEq, val: INT ← 0;
IF MAX[ListLength[top], ListLength[bot]] > 12 THEN {
UniqueIndex ← UniqueIndex+1;
RETURN[IO.PutFR["%g-Lrg-%g", IO.rope[type], IO.int[UniqueIndex]]]};
FOR ii: INT IN [0..12) DO
topN: ROPE ← ListIndexItem[top, ii];
botN: ROPE ← ListIndexItem[bot, ii];
IF ii IN [6..7] THEN LOOP;
topSig    ← (topSig*2) +(IF topN#NIL THEN 1 ELSE 0);
botSig    ← (botSig*2) +(IF botN#NIL THEN 1 ELSE 0);
tbEq    ← (tbEq*2) +(IF Rope.Equal[topN, botN] THEN 1 ELSE 0);
ENDLOOP;
val ← (topSig*1024+botSig)*1024+tbEq;
name ← type.Cat["-"];
name ← name.Cat[Convert.RopeFromInt[from: val, base: 32, showRadix: FALSE]];
FOR ins ← ins,  ins.rest WHILE ins#NILDO
val ← Index[ins.first];
name ← name.Cat[Convert.RopeFromInt[from: val, base: 32, showRadix: FALSE]] ENDLOOP;
name ← name.Cat["-"];
FOR outs ← outs, outs.rest WHILE outs#NILDO
val ← Index[outs.first];
name ← name.Cat[Convert.RopeFromInt[from: val, base: 32, showRadix: FALSE]] ENDLOOP };
WriteOutNewDesign: PUBLIC PROC[design: CD.Design, newName: ROPE] = {
CDSimpleOps.RenameDesign[design, newName];
[ ] ← CDIO.WriteDesign[design, newName] };
GetDesign: PUBLIC PROC[ref: REF] RETURNS[design: CD.Design] = {
WITH ref SELECT FROM
text:   REF TEXT => design ← CDIO.ReadDesign[Rope.FromRefText[text]];
designFile: Rope.ROPE => design ← CDIO.ReadDesign[designFile];
designRef: CD.Design => design ← designRef;
ENDCASE      => ERROR};
NFS, NewFrameSeq: PUBLIC PROC[
module:  ROPE,
xory:   XorY,
listTopLt:  LIST OF Frame,
orient:  CD.Orientation ← CD.original ]
RETURNS[frame: Frame] = {
count: INT ← 0;
FOR list: LIST OF Frame ← listTopLt, list.rest WHILE list # NIL DO
IF list.first=NIL THEN LOOP;
count ← count+1 ENDLOOP;
frame ← NEW[CDFrame.FrameSeq[count]];
frame.xory ← xory;
frame.orient ← orient;
frame.shell ← NEW[CDFrame.ShellRec ← [name: module]];
count ← (IF xory=x THEN 0 ELSE count-1);
FOR list: LIST OF Frame ← listTopLt, list.rest WHILE list # NIL DO
IF list.first=NIL THEN LOOP;
frame[count] ← list.first;
count ← count + (IF xory=x THEN 1 ELSE -1) ENDLOOP};
NFSFUP, NewFrameSeqFromListUserProc: PUBLIC PROC[
module:  ROPE,
xory:   XorY,
listTopLt:  LIST OF UserProc,
orient:  CD.Orientation ← CD.original ]
RETURNS[frame: Frame] = {
count: INT ← 0;
FOR list: LIST OF UserProc ← listTopLt, list.rest WHILE list # NIL DO
IF list.first=NIL THEN LOOP;
count ← count+1 ENDLOOP;
frame ← NEW[CDFrame.FrameSeq[count]];
frame.xory ← xory;
frame.orient ← orient;
frame.shell ← NEW[CDFrame.ShellRec ← [name: module]];
count ← (IF xory=x THEN 0 ELSE count-1);
FOR list: LIST OF UserProc ← listTopLt, list.rest WHILE list # NIL DO
refProc: REF UserProc ← NEW[UserProc ← list.first];
IF list.first=NIL THEN LOOP;
frame[count] ← NEW[CDFrame.FrameSeq[0]];
frame[count].data ← refProc;
count ← count + (IF xory=x THEN 1 ELSE -1) ENDLOOP};
ShowObject: PUBLIC PROC[cell: CD.Object] = {
design: CD.Design ← CDOps.CreateDesign[IFUPW.cmos];
viewer: ViewerClasses.Viewer ← CDViewer.CreateViewer[design];
CDOps.AddAnObject[design, cell, [0, 0]];
CDViewer.ShowAndScale[viewer, CDExtras.BoundingBox[design]]};
Show5Objects: PUBLIC PROC [bottom, right, top, left, middle: CD.Object] = {
design: CD.Design ← CDOps.CreateDesign[IFUPW.cmos];
viewer: ViewerClasses.Viewer ← CDViewer.CreateViewer[design];
maxX: INTMAX[
IF top=NIL  THEN 0 ELSE CD.InterestSize[top].x,
IF bottom=NILTHEN 0 ELSE CD.InterestSize[bottom].x];
maxY: INTMAX[
IF left=NILTHEN 0 ELSE CD.InterestSize[left].y,
IF right=NILTHEN 0 ELSE CD.InterestSize[right].y];
CDOps.SetInstList[design, NIL];
CDOps.AddAnObject[design, left,  [-CD.InterestSize[left].x, 0]];
CDOps.AddAnObject[design, bottom, [0, -CD.InterestSize[bottom].y]];
CDOps.AddAnObject[design, top,  [0, maxY]];
CDOps.AddAnObject[design, right,  [maxX, 0]];
CDOps.AddAnObject[design, middle, [0, 0]];
CDViewer.ShowAndScale[viewer, CDExtras.BoundingBox[design]]};
ShowFrameBlock: PUBLIC PROC[frame: Frame] ~ {
designB: CD.Design    ← CDOps.CreateDesign[CDSil.cdsil];
viewerB: ViewerClasses.Viewer ← CDViewer.CreateViewer[designB];
cellB:  CD.Object    ← CDFrame.FrameToObject[frame, designB, FALSE];
CDSimpleOps.RenameDesign[designB, "ShowFrameBlock"];
CDOps.AddAnObject[designB, cellB, [0, 0]];
RepositionDesignViewer[designB, viewerB]};
AssembleFrame: PUBLIC PROC[
ref:  REF,
frame:  REF CDFrame.FrameSeq,
cmd:  Commander.Handle,
name:  ROPE ← NIL ] = {
design, designB: CD.Design;
cell,  cellB:  CD.Object;
done:  BOOLFALSE;
impl:  BOOLTRUE;
block:  BOOLTRUE;
write:  BOOLFALSE;
plot:  BOOLFALSE;
IF name=NIL AND frame.shell#NIL THEN name ← frame.shell.name;
IF frame.shell=NIL OR NOT Rope.Equal[frame.shell.name, name] THEN {
FOR index: INT IN [0..frame.seqSize) DO
AssembleFrame[ref, frame[index], cmd, name] ENDLOOP;
RETURN};
design ← GetDesign[ref];
IF cmd#NIL AND cmd.commandLine#NIL THEN {
IF Rope.Find[cmd.commandLine,"-i",  0,FALSE]#-1 THEN impl ← NOT impl;
IF Rope.Find[cmd.commandLine,"-b",  0,FALSE]#-1 THEN block ← NOT block;
IF Rope.Find[cmd.commandLine,"-w", 0,FALSE]#-1 THEN write ← NOT write;
IF Rope.Find[cmd.commandLine,"-p",  0,FALSE]#-1 THEN plot  ← NOT plot };
IF impl THEN {
viewer:  ViewerClasses.Viewer ← CDViewer.CreateViewer[design];
CDSimpleOps.RenameDesign[design, name];
CDOps.SetInstList[design, NIL];
cell ← CDFrame.FrameToObject[frame, design];
CDOps.AddAnObject[design, cell, [0, 0]];
RepositionDesignViewer[design,   viewer]};
IF block THEN {
designB: CD.Design    ← CDOps.CreateDesign[CDSil.cdsil];
viewerB: ViewerClasses.Viewer ← CDViewer.CreateViewer[designB];
CDSimpleOps.RenameDesign[designB, name.Cat["Block"]];
cellB ← CDFrame.FrameToObject[frame, designB];
CDOps.AddAnObject[designB, cellB, [0, 0]];
RepositionDesignViewer[designB, viewerB]};
IF cell=NIL THEN {cell ← cellB; design ← designB};
IF write THEN WriteOutNewDesign[design, name];
IF plot THEN PlotDesign[design, [0,0], CD.InterestSize[cell]] };
Register: PUBLIC PROC [userProc: PWUserProc, name: ROPE] = {PW.Register[userProc, name]};
ByteBitFromIndex: PUBLIC PROC[index: INT, rp: RowParams]
RETURNS[byte, bit: INT] = {
byte ← IF rp.seq THEN index /  rp.rngBit ELSE index MOD rp.rngByte;
bit  ← IF rp.seq THEN index MOD rp.rngBit ELSE index / rp.rngByte };
ByteBitToIndex: PUBLIC PROC[byte, bit: INT, rp: RowParams]
RETURNS[index: INT] = {
RETURN[IF rp.seq
THEN byte * rp.rngBit  + bit
ELSE bit  * rp.rngByte + byte]};
RepositionDesignViewer: PUBLIC PROC[design: CD.Design, viewer: ViewerClasses.Viewer] =
{CDViewer.ShowAndScale[viewer, CDExtras.BoundingBox[design]]};
PlotDesign: PUBLIC PROC[design: CD.Design, pos: Location, sPos: Size ← [0, 0]] = {
command: CDSequencer.Command ← NEW[CDSequencer.CommandRec ←
[design: design, pos: pos, sPos: sPos, a: $VersatecAutoPlot]];
CDSequencer.ExecuteCommand[command, design, $VersatecAutoPlot]};
RenameObjAndAssignRowPins: PUBLIC PROC[
design:   CD.Design,
row:    CD.Object,
newObjName: ROPE,
identity:   BOOL   ← TRUE,
top:    LIST OF REF ← NIL,
bot:    LIST OF REF ← NIL,
leftCtl:   List   ← NIL,
rightCtl:   List   ← NIL,
rp:     RowParams ← IFUDataColNSeq ]
RETURNS[newObject: CD.Object] = {
AssignNames: PinNameProc = {
oldPinName: ROPE ← CDPinObjects.GetName[pin];
IF identity THEN RETURN[oldPinName];
SELECT side FROM
left  => {
index: INT ← Rope.SkipTo[oldPinName, 0, "0123456789"];
IF oldPinName.Find[VDD]>=0 THEN RETURN[oldPinName];
IF oldPinName.Find[GND]>=0 THEN RETURN[oldPinName];
index ← Convert.IntFromRope[Rope.Substr[oldPinName, index]];
name ← ListIndexItem[leftCtl, index]};
right  => {
index: INT ← Rope.SkipTo[oldPinName, 0, "0123456789"];
IF oldPinName.Find[VDD]>=0 THEN RETURN[oldPinName];
IF oldPinName.Find[GND]>=0 THEN RETURN[oldPinName];
index ← Convert.IntFromRope[Rope.Substr[oldPinName, index]] - ListLength[leftCtl];
name ← ListIndexItem[rightCtl, index]};
top, bottom => {
list:  List;
byte, bit: INT;
column: INT ← ((pin.location.x MOD cellWidth)-leftTail)/metPitch;
[byte, bit]  ← ByteBitFromIndex[pin.location.x/cellWidth, rp];
list    ← ExpandList[byte, bit, IF side=top THEN top ELSE bot];
list    ← FixGVInList[list];
name    ← ListIndexItem[list, column];
IF name=NIL THEN ERROR};
ENDCASE   => ERROR};
newObject ← RenameObjAndPins[design, row, newObjName, AssignNames]};
RenameObjAndPins: PUBLIC PROC[
design:   CD.Design,
object:   CD.Object,
newObjName: ROPE,
pinNameProc: PinNameProc]
RETURNS[newObject: CD.Object] = {
KeepPinOnEdge: CDPinObjects.InstanceEnumerator = {
newRope: ROPE;
newInst: CD.Instance;
side: CDFrame.Side5;
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:   CDPinObjects.CreatePinOb[inst.ob.size],
location:  inst.location,
orientation: inst.orientation ]];
CDProperties.CopyProps[inst.properties, newInst];
CDPinObjects.SetName[newInst, newRope];
newCellPtr.contents ← CONS[newInst, newCellPtr.contents];
};
newCellPtr: CD.CellPtr;
inst:   CD.Instance ← NEW[CD.InstanceRep ← [ob: object]];
CDProperties.PutPropOnInstance[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]];
PW.IncludeInDirectory[design, newObject, newObjName];
RETURN[newObject] };
FillerCell: PUBLIC PROC
[design: CD.Design, obj: CD.Object, objSide: Side, width: INT, copyPins: BOOLFALSE]
RETURNS [cell: CD.Object] = {
KeepPinOnEdge: PWPins.InstanceEnumerator = {
side:  Side;
layer:  CD.Layer ← CDPinObjects.GetLayer[inst];
name:  ROPE ← CDPinObjects.GetName[inst];
side ← PWPins.GetSide[obj, inst];
IF side#objSide THEN RETURN[FALSE];
SELECT side FROM
top, bottom => {
locX: INT ← inst.location.x-rRect.x1;
AddRet[cell, [inst.ob.size.x, width], [locX, 0], layer];
IF copyPins THEN {
PutPin[cell, [inst.ob.size.x, pinDim], [locX, 0],     layer, name];
PutPin[cell, [inst.ob.size.x, pinDim], [locX, width-pinDim], layer, name]}};
ENDCASE => {
locY: INT ← inst.location.y-rRect.y1;
AddRet[cell, [width, inst.ob.size.y], [0, locY], layer];
IF copyPins THEN {
PutPin[cell, [pinDim, inst.ob.size.y], [0,    locY], layer, name];
PutPin[cell, [pinDim, inst.ob.size.y], [width-pinDim, locY], layer, name]}}};
rRect, fRect: CD.Rect;
pinDim: INTMIN[8, width/2]; IF copyPins AND pinDim = 0 THEN ERROR;
cell ← CDCells.CreateEmptyCell[];
rRect ← CD.InterestRect[obj];
fRect ← SELECT objSide FROM
top, bottom => [0, 0, rRect.x2-rRect.x1, width],
left, right => [0, 0, width, rRect.y2-rRect.y1],
ENDCASE => ERROR;
CDCells.SetInterestRect[cell, fRect];
[] ← PWPins.EnumerateDeepPins[obj, KeepPinOnEdge];
[] ← PW.IncludeInDirectory[design, cell, "Filler"] };
END.