IcPackImpl.mesa
Copyright Ó 1988 by Xerox Corporation. All rights reserved.
Don Curry August 30, 1988 2:31:03 pm PDT
Bertrand Serlet May 7, 1988 10:44:45 pm PDT
DIRECTORY
Basics, BondingPads, CD, CDBasics, CDCells, CDCommandOps, CDDirectory, CDInstances, CDIO, CDLayers, CDOps, CDPanelFonts, CDProperties, CDRects, CDSatellites, CDSequencer, CDTexts, CDViewer, CMosB, Commander, CommandTool, Convert, Core, CoreClasses, CoreGeometry, CoreOps, CoreProperties, FS, IcPack, IO, PGACoordXlate, PWCore, RefTab, Rope, RopeList, Sisyph, TerminalIO, ViewerClasses, ViewerOps;
IcPackImpl: CEDAR PROGRAM
IMPORTS
BondingPads, CD, CDBasics, CDCells, CDCommandOps, CDDirectory, CDInstances, CDIO, CDLayers, CDOps, CDPanelFonts, CDProperties, CDRects, CDSatellites, CDSequencer, CDTexts, CDViewer, CMosB, Commander, CommandTool, Convert, CoreClasses, CoreGeometry, CoreOps, CoreProperties, FS, IO, PGACoordXlate, PWCore, RefTab, Rope, RopeList, Sisyph, TerminalIO, ViewerOps
EXPORTS IcPack
SHARES Sisyph
~ BEGIN
Types
Side:   TYPE = CoreGeometry.Side;
Triplets:  TYPE = ARRAY Side OF LIST OF Triplet ← ALL[NIL];
Triplet:  TYPE = RECORD[pad, pin, text: CD.Instance ← NIL];
SignalPins: TYPE = PGACoordXlate.SignalPins;
tech:   CD.Technology ← CMosB.cmosB;
buildIcPackDoc: IO.ROPE ← "BuildIcPack deviceCoreFile packageDaleFile
-o => keep Outside pad pins (when there are dual pad rows).
example: BuildIcPack MapCache PGA300DynaBus
";
genEPListsDoc: IO.ROPE ← "GenExpertPinLists designName [cellName]\n";
genCPListsDoc: IO.ROPE ← "GenCoordPinList designName [cellName]\n";
genMTSPinList: IO.ROPE ← "GenMTSPinList designName [cellName]\n";
BuildIcPack
BuildIcPack: PUBLIC PROC[device: Core.CellType, packageNm: IO.ROPE, keepOutside: BOOL] = {
cache: Core.CellType ← CacheCell[device];
BuildFromCache[cache, packageNm, keepOutside]};
BuildIcPackComm: Commander.CommandProc = {
deviceNm:  IO.ROPE;
packageNm:  IO.ROPE;
overFlow:  IO.ROPE;
argv:    CommandTool.ArgumentVector ← CommandTool.Parse[cmd];
keepOutside:  BOOLFALSE;
mainCell:   Core.CellType ← NIL;
devCacheCell: Core.CellType ← NIL;
FOR ii: INT IN [1..argv.argc) DO
rope: Rope.ROPE ← CommandTool.ArgN[cmd, ii];
SELECT rope.Fetch[0] FROM
'- => SELECT rope.Fetch[1] FROM
'o, 'O => keepOutside ← TRUE;
ENDCASE => {cmd.out.PutRope[buildIcPackDoc]; RETURN[$Failure]};
ENDCASE => {overFlow ← deviceNm; deviceNm ← packageNm; packageNm ← rope}
ENDLOOP;
IF deviceNm=NIL OR overFlow#NIL THEN
{cmd.out.PutRope[buildIcPackDoc]; RETURN[$Failure]};
mainCell ← PWCore.Retrieve[deviceNm ! FS.Error => {mainCell ← NIL; CONTINUE}];
IF mainCell=NIL THEN
{cmd.out.PutF["Device: %g not found\n", IO.rope[deviceNm]]; RETURN[$Failure]};
devCacheCell ← CacheCell[mainCell];
BuildFromCache[devCacheCell, packageNm, keepOutside]};
MakeCache: PROC[cell: Core.CellType] RETURNS[cacheCell: Core.CellType] = {
deviceNm:  IO.ROPE ← Root[CoreOps.GetCellTypeName[cell], "IcPack"];
cacheCellNm: IO.ROPE ← deviceNm.Cat["IcPackCache"];
oldPriority:  CedarProcess.Priority ← CedarProcess.GetPriority[];
CedarProcess.SetPriority[background];
BondingPads.MarkBondingPads[cell];
cacheCell ← CacheCell[cell];
[]𡤌oreOps.SetCellTypeName[cacheCell, cacheCellNm];
[]𡤌oreIO.ReportSaveCellType[cacheCell];
CedarProcess.SetPriority[oldPriority]};
BuildFromCache: PROC
[cacheCell: Core.CellType, packageNm: IO.ROPE, keepOutside: BOOL] = {
cacheNm:   IO.ROPE  ← CoreOps.GetCellTypeName[cacheCell];
deviceNm:  IO.ROPE  ← Root[cacheNm, "IcPack"];
newDesignNm: IO.ROPE  ← deviceNm.Cat["IcPack"];
newObjNm:  IO.ROPE  ← deviceNm.Cat["IcPack"];
design:   CD.Design ← CDIO.ReadDesign[from: packageNm, wDir: NIL];
grid:    INT;
package:   CD.Object;
device:   CD.Object;
packCenter:  CD.Position;
devCenter:  CD.Position;
offset:    CD.Position;
IF design=NIL THEN
{TerminalIO.PutF["Package: %g not found\n", IO.rope[packageNm]]; RETURN};
package  ← CDOps.InstList[design].first.ob;
packCenter ← CDBasics.Center[CD.InterestRect[package]];
grid   ← design.technology.lambda*2;
CDOps.SetMutability[design];
CDOps.RemoveInstance[design, CDOps.InstList[design].first];
device   ← BuildPadModel[cacheCell, keepOutside];
devCenter ← CDBasics.Center[CD.InterestRect[device]];
offset   ← CDBasics.SubPoints[packCenter, devCenter];
offset.x  ← ((offset.x+grid/2)/grid)*grid;
offset.y  ← ((offset.y+grid/2)/grid)*grid;
[]�lls.IncludeOb[design, package, device, [offset]];
[]�lls.ToSequenceMode[package];
IF NOT CDDirectory.Rename[design, package, newObjNm].done THEN ERROR;
IF NOT CDOps.RenameDesign[design, newDesignNm] THEN ERROR;
[]�Ops.IncludeObject[design, package, [[0,0]]];
CDLayers.SetLayerWidth[design, CDLayers.CurrentLayer[design], tech.lambda];
[]�Viewer.CreateViewer[design];
CDSequencer.ExecuteCommand[key: $ResetScaleTop, design: design, queue: dontQueue];
IF NOT CDIO.WriteDesign[design, newDesignNm] THEN ERROR};
Root: PROC[rope, match: IO.ROPE] RETURNS[IO.ROPE] =
{RETURN[rope.Substr[0, rope.Index[0, match]]]};
ChipnDale Command CreateIcPack
CreateIcPack:   PROC [comm: CDSequencer.Command] ~ {
selectedName: IO.ROPE;
shortName:  IO.ROPE;
iconName:  IO.ROPE;
cellCode:   IO.ROPE;
scaleRope:  IO.ROPE;
keepOutside:  BOOL;
scale:    INT ← 40;
TerminalIO.PutRope["Create layout scaled bonding icon with atomic publics\n"];
TerminalIO.PutRope[" Uses current layer, layer width, grid and font to construct icon\n"];
IF comm.key = $CreateIcPackFromSch
THEN {
selected: CD.Instance ← CDOps.TheInstance[comm.design, "CreateFSMIcon\n"];
IF selected=NIL THEN RETURN;
selectedName ← CDDirectory.Name[selected.ob, comm.design];
IF selectedName.IsEmpty[] THEN
{TerminalIO.PutF["*** Selected schematic has no name.\n"]; RETURN};
cellCode ← IO.PutFR["Sisyph.ES[\"%g\", cx]", IO.rope[selectedName]]}
ELSE {cellCode ← TerminalIO.RequestRope[" Code: "]};
cellCode  ← IO.PutFR["IcPack.FlatCell[%g]", IO.rope[cellCode]];
shortName ← TerminalIO.RequestRope[" Short name: "];
IF shortName=NIL THEN shortName ← selectedName;
shortName ← shortName.Substr[0, shortName.Index[0, "."]];
IF shortName=NIL THEN {TerminalIO.PutRope[" . . . aborted\n"]; RETURN};
iconName ← shortName.Concat["Bonding.icon"];
scaleRope ← TerminalIO.RequestRope[" Reduction Factor (default 40): "];
IF scaleRope#NIL THEN scale ← Convert.IntFromRope[scaleRope];
keepOutside ← TerminalIO.Confirm[" Include outside row of dual pads rows?"];
MakeAndInsertIcon[comm.design, comm.pos, iconName, cellCode, scale, keepOutside]};
MakeAndInsertIcon: PROC
[design: CD.Design, pos: CD.Position, iconName, cellCode: IO.ROPE, scale: INT ← 40, keepOutside: BOOLFALSE]~{
icon:   CD.Object;
cell:   Core.CellType;
cx:    Sisyph.Context ← Sisyph.Create[design];
grid:   INT   ← CDOps.GetGrid[design];
pinWidth: INT   ← CDLayers.LayerWidth[design, CD.commentLayer];
font:   CDTexts.CDFont ← CDPanelFonts.CurrentFont[design];
IF CDDirectory.Fetch[design, iconName]#NIL THEN
{TerminalIO.PutF["*** The icon %g already exists!\n", IO.rope[iconName]]; RETURN};
cell ← NARROW[Sisyph.EvalToRef[cx, cellCode]];
icon ← BuildPadModel[cell, keepOutside, grid, pinWidth, scale, font];
CDProperties.PutObjectProp[icon, Sisyph.mode.extractProcProp, $SisyphExtractCellIcon];
CDProperties.PutObjectProp[icon, $CodeFor, cellCode];
CDCells.SetSimplificationTreshhold[cell: icon, val: 30, inPixels: TRUE];
IF NOT CDDirectory.Include[design, icon, iconName] THEN ERROR;
[] ← CDOps.IncludeObjectI[design, icon, pos];
TerminalIO.PutF[" %g insterted into design.\n", IO.rope[iconName]]};
Build Pad Model
BuildPadModel: PUBLIC PROC[
cell:   Core.CellType,
keepOutside: BOOL    ← FALSE,
refGrid:  INT    ← 0, -- default 2 lambda
pinWidth: INT    ← 0, -- default 1/2 lambda
scale:   INT    ← 40,
refFont:  CDTexts.CDFont ← NIL ]
RETURNS[obj: CD.Object] ~ {
ToGrid: PROC [x: CD.Number] RETURNS [v: CD.Number] ~
{v ← IF x>=0 THEN ((x+grid/2)/grid)*grid ELSE ((x-grid/2)/grid)*grid};
ScaleIR: PROC [r: CD.Rect] RETURNS [v: CD.Rect] ~ {v ← [
x1:  r.x1/scale, x2:  r.x2/scale,
y1: r.y1/scale, y2: r.y2/scale]};
size: CD.Position ← BondingPads.GetSize[cell];
grid:    INT   ← IF refGrid#0 THEN refGrid ELSE tech.lambda*2;
pWidth:   INT   ← IF pinWidth#0 THEN pinWidth ELSE tech.lambda;
cellName:   IO.ROPE  ← Root[CoreOps.GetCellTypeName[cell], "IcPack"];
basicLayer:  CD.Layer  ← CD.commentLayer;
sigLayer:   CD.Layer  ← CD.FetchLayer[tech, $blue];
vddLayer:  CD.Layer  ← CD.FetchLayer[tech, $red];
gndLayer:  CD.Layer  ← CD.FetchLayer[tech, $green];
sclSize:   CD.Position  ← [ToGrid[size.x/scale]+pWidth, ToGrid[size.y/scale]+pWidth];
cRect:    CD.Rect  ← [0, 0, sclSize.x, sclSize.y];
guard:   CD.Number ← 2*pWidth;
font:    CDTexts.CDFont ← IF refFont#NIL
THEN refFont ELSE CDTexts.MakeFont["Xerox/TiogaFonts/Helvetica7", 4];
fontCorrection: CD.Number  ← -font.height/2 + font.origin.y;
triplets:   Triplets;
iList:    CD.InstanceList;
nmScale:   INT ← 4;
nmInst:   CD.Instance;
eachPublic: PROC[wire: Core.Wire] = {
name:  IO.ROPE ← AtomicName[CoreOps.GetFullWireName[cell.public, wire]];
text:  CD.Object ← CDTexts.Create[name, font, basicLayer];
instances: LIST OF CoreGeometry.Instance ←
NARROW[CoreProperties.GetWireProp[wire, $BondingPads]];
padLayer: CD.Layer ← SELECT TRUE FROM
name.Find["Gnd", 0, FALSE]#-1 => gndLayer,
name.Find["Vdd", 0, FALSE]#-1 => vddLayer,
ENDCASE        => sigLayer;
FOR instances ← instances, instances.rest WHILE instances#NIL DO
ir:    CD.Rect ← ScaleIR[CoreGeometry.BBox[instances.first]];
side:   Side ← NearestSide[ir, cRect];
ave:   CD.Position ← [(ir.x1+ir.x2)/2, (ir.y1+ir.y2)/2];
pinPos:  CD.Position ← SELECT side FROM
left  => [0,    ToGrid[ave.y-pWidth/2] ],
right  => [cRect.x2,  ToGrid[ave.y-pWidth/2] ],
top  => [ToGrid[ave.x-pWidth/2], cRect.y2 ],
ENDCASE => [ToGrid[ave.x-pWidth/2], 0    ];
pinSize: CD.Position ← SELECT side FROM
left  => [ave.x - cRect.x1, pWidth ],
right  => [cRect.x2 - ave.x, pWidth ],
top  => [cRect.y2 - ave.y, pWidth ],
ENDCASE => [ave.y - cRect.y1, pWidth ];
pinObj:  CD.Object ← CDRects.CreateRect[pinSize, basicLayer];
textPos: CD.Position ← SELECT side FROM
left  => [ir.x2+guard,  ave.y + fontCorrection],
right  => [ir.x1-guard,  ave.y + fontCorrection],
top  => [ave.x + fontCorrection, ir.y1-guard],
ENDCASE => [ave.x + fontCorrection, ir.y2+guard];
orient: CD.Orientation ← SELECT side FROM
left  => original,
right  => mirrorX,
top  => rotate270,
ENDCASE => rotate90X;
padObj: CD.Object  ← CDRects.CreateRect[CDBasics.SizeOfRect[ir], padLayer];
padInst: CD.Instance ← CDInstances.NewInst[padObj, [CDBasics.BaseOfRect[ir]]];
pinInst: CD.Instance ← CDInstances.NewInst[pinObj, [pinPos, orient]];
textInst: CD.Instance ← CDInstances.NewInst[text,  [textPos, orient]];
CDProperties.PutInstanceProp[padInst, Sisyph.mode.extractProcProp, $ExtractNull];
CDSatellites.Associate[master: pinInst, text: textInst];
triplets[side] ← CONS[[pad: padInst, pin: pinInst, text: textInst], triplets[side]];
ENDLOOP};
DO
nmFont: CDTexts.CDFont ← CDTexts.MakeFont["Xerox/TiogaFonts/Helvetica7", nmScale];
nmText:   CD.Object  ← CDTexts.Create[cellName, nmFont, basicLayer];
nmTextSz:  CD.Position ← CD.InterestSize[nmText];
nmPos:   CD.Position ← [sclSize.x/2-nmTextSz.x/2, sclSize.y/2];
nmInst ← CDInstances.NewInst[nmText, [nmPos]];
IF nmTextSz.x*3 > (cRect.x2 - cRect.x1) THEN EXIT;
nmScale ← nmScale*2 ENDLOOP;
obj ← CDCells.CreateEmptyCell[];
BondingPads.MarkBondingPads[cell];
[]𡤌oreOps.VisitRootAtomics[cell.public, eachPublic];
iList ← FilterOutsidePins[triplets, keepOutside, grid];
obj ← CDCells.CreateCell[il: CONS[nmInst, iList], ir: cRect];
CDCells.ToSequenceMode[obj]};
AddIfUnique: PROC[rope: IO.ROPE, ropes: LIST OF IO.ROPE] RETURNS[LIST OF IO.ROPE] =
{IF ~RopeList.Memb[ropes, rope] THEN ropes ← CONS[rope, ropes]; RETURN[ropes]};
SideNm: ARRAY Side OF IO.ROPE
[bottom: "Bottom",  top: "Top",  left: "Left",  right: "Right"];
Compare: PROC[side: Side, ir1, ir2: CD.Rect] RETURNS[ioSide: {in, out, equal}] = {
AboutTheSame: PROC[a1, a2, b1, b2: INT] RETURNS[same: BOOL] ← {
size:  INTMAX[b2-b1, a2-a1];
overLap: INTMIN[a2, b2] - MAX[a1, b1];
RETURN[((overLap*100)/size) > 90]}; -- more than 90% overlap
SELECT side FROM
left  => {IF ir1.x2<ir2.x1 THEN RETURN[out]; IF ir1.x1>ir2.x2 THEN RETURN[in]};
right  => {IF ir1.x2<ir2.x1 THEN RETURN[in]; IF ir1.x1>ir2.x2 THEN RETURN[out]};
top  => {IF ir1.y2<ir2.y1 THEN RETURN[in]; IF ir1.y1>ir2.y2 THEN RETURN[out]};
bottom => {IF ir1.y2<ir2.y1 THEN RETURN[out]; IF ir1.y1>ir2.y2 THEN RETURN[in]};
ENDCASE;
SELECT side FROM
left, right => {IF AboutTheSame[ir1.x1, ir1.x2, ir2.x1, ir2.x2] THEN RETURN[equal]};
top, bottom=> {IF AboutTheSame[ir1.y1, ir1.y2, ir2.y1, ir2.y2] THEN RETURN[equal]};
ENDCASE;
ERROR}; -- pads overlap in range (0..90%)
FilterOutsidePins: PROC[triplets: Triplets, keepOutside: BOOL, grid: INT]
RETURNS[iList: CD.InstanceList]= {
BBox: PROC[inst: CD.Instance] RETURNS[CD.Rect] =
{RETURN[CDBasics.MapRect[inst.ob.bbox, inst.trans]]};
TextNm: PROC[text: CD.Instance] RETURNS[IO.ROPE] =
{RETURN[NARROW[text.ob.specific, CDTexts.TextSpecific]^.text]};
FOR side: Side IN Side DO
HalfPin: PROC[oldPin: CD.Object] RETURNS[newPin: CD.Object] = {
oldSize: CD.Position ← CD.InterestSize[oldPin];
newPin ← CDRects.CreateRect[[oldSize.x, oldSize.y/2], oldPin.layer]};
inNms: LIST OF IO.ROPE ← NIL;
outNms: LIST OF IO.ROPE ← NIL;
ins:  LIST OF Triplet ← NIL;
outs:  LIST OF Triplet ← NIL;
FOR trips: LIST OF Triplet ← triplets[side], trips.rest WHILE trips#NIL DO
AddTo: PROC[row: {in, out}] = {IF row=in
THEN {ins ← CONS[trip, ins]; inNms ← AddIfUnique[tripNm, inNms]}
ELSE {outs ← CONS[trip, outs]; outNms ← AddIfUnique[tripNm, outNms]}};
trip:  Triplet ← trips.first;
tripNm: IO.ROPE ← TextNm[trip.text];
tripIR:  CD.Rect ← BBox[trip.pad];
IF ins=NIL THEN {AddTo[in]; LOOP};
SELECT Compare[side, tripIR, BBox[ins.first.pad]] FROM
equal => {AddTo[in]; LOOP};
in  => {
IF outs#NIL THEN ERROR;
outs  ← ins;   ins ← NIL;
outNms ← inNms; inNms ← NIL;
AddTo[in]; LOOP};
out => {
IF outs#NIL AND Compare[side, tripIR, BBox[outs.first.pad]]#equal
THEN ERROR;
AddTo[out]; LOOP};
ENDCASE;
ENDLOOP;
If keepOutside (and there are two rows) then:
Narrow all pins.
Shift outside pins by grid/2.
Delete text of outside pins.
FOR ins ← ins, ins.rest WHILE ins#NIL DO
IF keepOutside AND outNms#NIL THEN ins.first.pin.ob ← HalfPin[ins.first.pin.ob];
iList ← CONS[ins.first.pin, CONS[ins.first.text, CONS[ins.first.pad, iList]]] ENDLOOP;
IF keepOutside
THEN {
IF outNms#NIL THEN
TerminalIO.PutF["%g outside pins shifted to half grid points.\n",
IO.rope[SideNm[side]]];
FOR outNms ← outNms, outNms.rest WHILE outNms#NIL DO
TerminalIO.PutF["Deleted %g outside %g satellites\n",
IO.rope[SideNm[side]], IO.rope[outNms.first]] ENDLOOP;
FOR outs ← outs, outs.rest WHILE outs#NIL DO
ToHalfGrid: PROC[av, old: INT] RETURNS[new: INT] = {
new ← old + (IF (av-old+newPinW/2)>0
THEN grid/2
ELSE -grid/2)};
ave:   CD.Position ← CDBasics.Center[BBox[outs.first.pad]];
newPinW: INT   ← CD.InterestSize[outs.first.pin.ob].y/2;
oldPos:  CD.Position ← outs.first.pin.trans.off;
nm:   IO.ROPE  ← TextNm[outs.first.text];
outs.first.pin.ob ← HalfPin[outs.first.pin.ob];
CDProperties.PutInstanceProp[outs.first.pin, $SignalName, nm];
SELECT side FROM
left  => outs.first.pin.trans.off.y ← ToHalfGrid[ave.y, oldPos.y];
right  => outs.first.pin.trans.off.y ← ToHalfGrid[ave.y, oldPos.y];
top  => outs.first.pin.trans.off.x ← ToHalfGrid[ave.x, oldPos.x];
ENDCASE => outs.first.pin.trans.off.x ← ToHalfGrid[ave.x, oldPos.x];
iList ← CONS[outs.first.pin, CONS[outs.first.pad, iList]];
ENDLOOP}
ELSE {
FOR outNms ← outNms, outNms.rest WHILE outNms#NIL DO
TerminalIO.PutF["Deleted %g outside pin(s): %g\n",
IO.rope[SideNm[side]], IO.rope[outNms.first]] ENDLOOP;
FOR outs ← outs, outs.rest WHILE outs#NIL DO
iList ← CONS[outs.first.pad, iList] ENDLOOP}
ENDLOOP};
Atomic Flat Cells
AtomicName: PUBLIC PROC[strucName: IO.ROPE] RETURNS[atomicName: IO.ROPE] = {
replaceBrackets:Rope.TranslatorType~{RETURN[SELECT old FROM '[=>'(,']=>'),ENDCASE=>old]};
atomicName ← Rope.Translate[base: strucName, translator: replaceBrackets]};
StructuredName: PUBLIC PROC[atomicName: IO.ROPE] RETURNS[strucName: IO.ROPE] = {
replaceParens: Rope.TranslatorType~{RETURN[SELECT old FROM '(=>'[,')=>'],ENDCASE=>old]};
strucName ← Rope.Translate[base: atomicName, translator: replaceParens]};
AtomicTopWires: PROC[ref: Core.CellType]
RETURNS[publics, internalOnlys: Core.Wires, actual: Core.Wire] = {
eachPair: CoreOps.EachWirePairProc = {
actualName: IO.ROPEIF publicWire.size=0
THEN AtomicName[CoreOps.GetFullWireName[ref.public, publicWire]] ELSE NIL;
[] ← CoreOps.SetShortWireName[actualWire, actualName];
IF CoreOps.Member[internalOnlys, actualWire] THEN RETURN;
IF CoreOps.Member[publics,   actualWire] THEN RETURN;
IF actualName=NIL
THEN internalOnlys ← CONS[actualWire, internalOnlys]
ELSE {
newList: LIST OF CoreGeometry.Instance ← NIL;
instances: LIST OF CoreGeometry.Instance ←
NARROW[CoreProperties.GetWireProp[publicWire, $BondingPads]];
FOR instances ← instances, instances.rest WHILE instances#NIL DO
newList ← CONS[instances.first, newList] ENDLOOP;
CoreProperties.PutWireProp[actualWire, $BondingPads, newList];
publics ← CONS[actualWire, publics];
FOR pubs: Core.Wires ← publics, pubs.rest WHILE pubs#NIL AND pubs.rest#NIL DO
TwoWires: TYPE  = RECORD[w1, w2: Core.Wire];
n1:   IO.ROPE ← CoreOps.GetShortWireName[pubs.first];
n2:   IO.ROPE ← CoreOps.GetShortWireName[pubs.rest.first];
SELECT Rope.Compare[n1, n2, FALSE] FROM
less  => EXIT;
greater => [pubs.rest.first, pubs.first] ← TwoWires[pubs.first, pubs.rest.first];
ENDCASE => ERROR ENDLOOP}};
actual ← CoreOps.CopyWire[ref.public];
[] ← CoreOps.VisitBinding[actual, ref.public, eachPair]};
FlatCell: PUBLIC PROC[ref: Core.CellType] RETURNS[cell: Core.CellType] = {
publics: Core.Wires;
internals: Core.Wires;
inst:  CoreClasses.CellInstance ← NEW[ CoreClasses.CellInstanceRec ← [type: ref]];
name:  IO.ROPE ← CoreOps.GetCellTypeName[ref];
size:  CD.Position ← BondingPads.GetSize[ref];
[publics, internals, inst.actual] ← AtomicTopWires[ref];
FOR pubs: Core.Wires ← publics, pubs.rest WHILE pubs#NIL DO
internals ← CONS[pubs.first, internals] ENDLOOP;
cell ← CoreClasses.CreateRecordCell[
public:  CoreOps.CreateWire[publics],
internal:  CoreOps.CreateWire[internals],
instances:  LIST[inst],
name:   name.Cat["IcPackCell"] ];
PWCore.SetLayout[cell, $AbutX];
CoreProperties.PutCellTypeProp[cell, $BondingFrameSize, NEW[CD.Position ← size]]};
CacheCell: PUBLIC PROC[ref: Core.CellType] RETURNS[cell: Core.CellType] = {
public: Core.Wire  ← CoreOps.CopyWire[ref.public];
internals: Core.Wires ← NIL;
eachPair: CoreOps.EachWirePairProc = {
actList:  LIST OF CoreGeometry.Instance ←
NARROW[CoreProperties.GetWireProp[actualWire, $BondingPads]];
subPubList: LIST OF CoreGeometry.Instance ←
NARROW[CoreProperties.GetWireProp[publicWire, $BondingPads]];
IF actList=NIL THEN {
FOR subPubList ← subPubList, subPubList.rest WHILE subPubList#NIL DO
actList ← CONS[subPubList.first, actList] ENDLOOP;
CoreProperties.PutWireProp[actualWire, $BondingPads, actList]}};
name:  IO.ROPE ← CoreOps.GetCellTypeName[ref];
size:  REF CD.Position ← NARROW[CoreProperties.GetCellTypeProp[ref, $BondingFrameSize]];
[] ← CoreOps.VisitBinding[public, ref.public, eachPair];
FOR i: INT IN [0..public.size) DO internals ← CONS[public[i], internals] ENDLOOP;
cell ← CoreClasses.CreateRecordCell[
public:  public,
internal:  CoreOps.CreateWire[internals],
instances:  NIL,
name:   name ];
CoreProperties.PutCellTypeProp[cell, $BondingFrameSize, size]};
NearestSide: PROC[sml, lrg: CD.Rect] RETURNS[side: Side ← left] ~ {
dist: INT ← ABS[lrg.x1 - sml.x1];
test: INT ← ABS[lrg.x2 - sml.x2]; IF test < dist THEN {dist ← test; side ← right};
test  ← ABS[lrg.y1 - sml.y1]; IF test < dist THEN {dist ← test; side ← bottom};
test  ← ABS[lrg.y2 - sml.y2]; IF test < dist THEN {dist ← test; side ← top}};
MakeTestObject: PROC[instances: LIST OF CoreGeometry.Instance] RETURNS[obj: CD.Object] = {
iList: CD.InstanceList ← NIL;
FOR instances ← instances, instances.rest WHILE instances#NIL DO
inst: CD.Instance ← CDInstances.NewInst[instances.first.obj, instances.first.trans];
iList ← CONS[inst, iList] ENDLOOP;
obj ← CDCells.CreateCell[il: iList];
CDCells.ToSequenceMode[obj]};
Gen Pin Cross References
GenPinListComm: Commander.CommandProc = {
argv:   CommandTool.ArgumentVector ← CommandTool.Parse[cmd];
designNm: IO.ROPE;
cellNm:  IO.ROPE;
cellType:  Core.CellType;
IF argv.argc<2 THEN {cmd.out.PutRope[genCPListsDoc]; RETURN[$Failure]};
designNm ← CommandTool.ArgN[cmd, 1];
cellNm  ← CommandTool.ArgN[cmd, 2];
cellType  ← GetDesignCellType[designNm, cellNm];
IF cellType=NIL THEN {
cmd.out.PutF["%g.%g not found.\n", IO.rope[designNm], IO.rope[cellNm]];
RETURN[$Failure]};
cellNm ← CoreOps.GetCellTypeName[cellType];
SELECT TRUE FROM
cmd.command.Find["GenExpertPinLists"]#-1  => {
GenExpertPinLists[cellType];
cmd.out.PutF["%g.pinsLeft ..Right ..Top ..Bottom written.\n", IO.rope[cellNm]]};
cmd.command.Find["GenCoordPinList"]#-1 => {
GenCoordPinList[cellType];
cmd.out.PutF["%g.pinCoords written.\n", IO.rope[cellNm]]};
cmd.command.Find["GenMTSPinList"]#-1   => {
GenMTSPinList[cellType];
cmd.out.PutF["%g.mtsPackage written.\n", IO.rope[cellNm]]};
ENDCASE => ERROR};
GenExpertPinLists: PUBLIC PROC[cell: Core.CellType] = {
WriteSideFile: PROC[sideRope: IO.ROPE, list: LIST OF IO.ROPE] = {
out: IO.STREAMFS.StreamOpen[name.Cat[".pins", sideRope], $create];
index: INT ← 0;
FOR list ← list, list.rest WHILE list#NIL DO
IF (index MOD 10) = 0 THEN out.PutRope["\n"];
index ← index+1;
IF list.first.Length[]=0
THEN out.PutRope["NC\n"]
ELSE out.PutF["%g\n", IO.rope[list.first]] ENDLOOP;
out.Close[]};
name:  IO.ROPE ← CoreOps.GetCellTypeName[cell];
names: ARRAY Side OF LIST OF IO.ROPEGetSidePinSignals[cell];
WriteSideFile[SideNm[left], RopeList.Reverse[names[left]]];
WriteSideFile[SideNm[right], RopeList.Reverse[names[right]]];
WriteSideFile[SideNm[top],       names[top]];
WriteSideFile[SideNm[bottom],      names[bottom]]};
GenCoordPinList: PUBLIC PROC[cell: Core.CellType] = {
name:  IO.ROPE    ← CoreOps.GetCellTypeName[cell];
out:  IO.STREAM   ← FS.StreamOpen[name.Cat[".pinCoords"], $create];
maxSize: INT     ← 2;
packageKey: ATOM     ← GetPackageKey[cell];
sigs:  LIST OF SignalPins ← GetSignalPins[cell];
FOR ss: LIST OF SignalPins ← sigs, ss.rest WHILE ss#NIL DO
maxSize ← MAX[maxSize, ss.first.nm.Length[]] ENDLOOP;
FOR ss: LIST OF PGACoordXlate.SignalPins ← sigs, ss.rest WHILE ss#NIL DO
IF ss.first.nm.Length[]=0 THEN LOOP;
out.PutRope[ss.first.nm];
THROUGH[ss.first.nm.Length[]..maxSize) DO out.PutChar[' ] ENDLOOP;
FOR pins: LIST OF NAT ← ss.first.pins, pins.rest WHILE pins#NIL DO
coord: PGACoordXlate.PGACoord ← PGACoordXlate.PinToPGACoord[packageKey, pins.first];
out.PutF[" %03g:%g",
IO.int  [pins.first],
IO.rope [PGACoordXlate.PGACoordToRope[coord]] ] ENDLOOP;
out.PutRope["\n"] ENDLOOP;
out.Close[]};
GenMTSPinList: PUBLIC PROC[cell: Core.CellType] = {
name:  IO.ROPE    ← CoreOps.GetCellTypeName[cell];
out:  IO.STREAM   ← FS.StreamOpen[name.Cat[".mtsPackage"], $create];
maxSize: INT     ← 0;
packageKey: ATOM     ← GetPackageKey[cell];
sigs:  LIST OF SignalPins ← GetSignalPins[cell];
out.PutF["Name %g;\n\n", IO.rope[name]];
out.PutF["Fixture PGA400;\n\n"];
FOR ss: LIST OF SignalPins ← sigs, ss.rest WHILE ss#NIL DO
maxSize ← MAX[maxSize, ss.first.nm.Length[]] ENDLOOP;
FOR ss: LIST OF PGACoordXlate.SignalPins ← sigs, ss.rest WHILE ss#NIL DO
setup: IO.ROPESELECT TRUE FROM
ss.first.nm.Find["Vdd"]#-1 => " /5V",
ss.first.nm.Find["Gnd"]#-1 => " /0V",
ENDCASE      => " ";
pins: LIST OF NAT ← ss.first.pins;
IF ss.first.nm.Length[]=0 THEN LOOP;
out.PutF[" Wire %g", IO.rope[StructuredName[ss.first.nm]]];
THROUGH[ss.first.nm.Length[]..maxSize) DO out.PutChar[' ] ENDLOOP;
out.PutF["%g", IO.rope[setup]];
SortPinsByCoords[pins, packageKey];
FOR pins ← pins, pins.rest WHILE pins#NIL DO
coord: PGACoordXlate.PGACoord ← PGACoordXlate.PinToPGACoord[packageKey, pins.first];
out.PutF[" %g", IO.rope[PGACoordXlate.PGACoordToRope[coord]] ] ENDLOOP;
out.PutRope[";\n"] ENDLOOP;
out.Close[]};
GetSignalPins: PUBLIC PROC[cell: Core.CellType] RETURNS[sigs: LIST OF SignalPins] = {
Note: The first SignalPins will be all the unconnected pins - nm.Length[]=0
InsertList: PROC[list: LIST OF IO.ROPE] = {
FOR list ← list, list.rest WHILE list#NIL DO
index ← index+1; sigs ← AddSignalPin[list.first, index, sigs] ENDLOOP};
packageKey: ATOM ← GetPackageKey[cell];
index:  INT ← 0;
names: ARRAY Side OF LIST OF IO.ROPEGetSidePinSignals[cell];
sigs ← PGACoordXlate.PGAFixedPins[packageKey];
InsertList[      names[top]];
InsertList[RopeList.Reverse[ names[right]]];
InsertList[RopeList.Reverse[ names[bottom]]];
InsertList[      names[left]]};
AddSignalPin: PROC[nm: IO.ROPE, pin: NAT, sigs: LIST OF SignalPins]
RETURNS[new: LIST OF SignalPins] = {
TwoSignalPins: TYPE = RECORD[n1, n2: SignalPins];
new ← CONS[[nm, LIST[pin]], sigs];
FOR temp: LIST OF SignalPins ← new, temp.rest WHILE temp#NIL AND temp.rest#NIL DO
SELECT Rope.Compare[temp.first.nm, temp.rest.first.nm, FALSE] FROM
equal  => {
temp.first.pins ← AddPin[temp.first.pins.first, temp.rest.first.pins];
temp.rest ← temp.rest.rest;
EXIT};
greater => [temp.first, temp.rest.first] ← TwoSignalPins[temp.rest.first, temp.first];
ENDCASE => EXIT ENDLOOP};
AddPin: PROC[pin: NAT, pins: LIST OF NAT] RETURNS[new: LIST OF NAT] = {
TwoNats: TYPE = RECORD[n1, n2: NAT];
new ← CONS[pin, pins];
FOR temp: LIST OF NAT ← new, temp.rest WHILE temp#NIL AND temp.rest#NIL DO
SELECT temp.first FROM
= temp.rest.first => {temp.rest ← temp.rest.rest; EXIT};
> temp.rest.first => [temp.first, temp.rest.first] ← TwoNats[temp.rest.first, temp.first];
ENDCASE   => EXIT ENDLOOP};
SortPinsByCoords: PROC[pins: LIST OF NAT, key: ATOM] = {
CoordRope: PROC[pin: NAT] RETURNS[rope: IO.ROPE] = {RETURN
[PGACoordXlate.PGACoordToRope[PGACoordXlate.PinToPGACoord[key, pin]]]};
DO
TwoNats: TYPE = RECORD[n1, n2: NAT];
done:  BOOLTRUE;
FOR temp: LIST OF NAT ← pins, temp.rest WHILE temp#NIL AND temp.rest#NIL DO
IF Rope.Compare[CoordRope[temp.first], CoordRope[temp.rest.first]] = greater THEN {
[temp.first, temp.rest.first] ← TwoNats[temp.rest.first, temp.first];
done ← FALSE} ENDLOOP;
IF done THEN EXIT ENDLOOP};
GetPackageKey: PROC[cell: Core.CellType] RETURNS[key: ATOM] = {
key ← NARROW[CoreProperties.GetCellTypeProp[cell, $Package]]};
GetSidePinSignals: PUBLIC PROC[cell: Core.CellType]
RETURNS[names: ARRAY Side OF LIST OF IO.ROPEALL[NIL]] = {
MakeList: PROC[wire: Core.Wire] RETURNS[list: LIST OF IO.ROPE] = {
FOR i: INT DECREASING IN [0..wire.size) DO
subPub: Core.Wire ← NARROW[RefTab.Fetch[table, wire[i]].val];
name:  IO.ROPE ← IF subPub=NIL
THEN "" ELSE CoreOps.GetShortWireName[subPub];
list ← CONS[name, list] ENDLOOP};
data:  CoreClasses.RecordCellType ← NARROW[cell.data];
wires:   ARRAY Side OF Core.Wire ← ALL[NIL];
device: CoreClasses.CellInstance;
table:  RefTab.Ref;
FOR side: Side IN Side DO
wires[side] ← CoreOps.FindWire[cell.public, SideNm[side]] ENDLOOP;
FOR i: INT IN [0..data.size) DO
IF ~CoreOps.GetCellTypeName[data[i].type].Substr[0, 3].Equal["Pkg"]
THEN device ← data[i] ENDLOOP;
table ← CoreOps.CreateBindingTable[device.actual, device.type.public];
FOR side: Side IN Side DO names[side] ← MakeList[wires[side]] ENDLOOP};
GetDesignCellType: PUBLIC PROC[designNm, cellNm: IO.ROPENIL]
RETURNS[cellType: Core.CellType ← NIL] = {
design: CD.Design ← GetDesign[designNm];
IF design#NIL THEN {
cx:    Sisyph.Context ← Sisyph.Create[design];
obj:   CD.Object   ← CDOps.InstList[design].first.ob;
objNm:  IO.ROPE   ← CDDirectory.Name[obj, design];
IF cellNm=NIL THEN cellNm ← objNm;
cellType ← Sisyph.ES[cellNm, cx]}};
GetDesign: PUBLIC PROC [name: IO.ROPE] RETURNS [design: CD.Design] = {
viewer: ViewerClasses.Viewer;
design ← CDViewer.FindDesign[name];
IF design#NIL THEN RETURN[design];
IF name.Length[]=0 THEN RETURN[NIL];
design ← CDIO.ReadDesign[name];
CDOps.SetMutability[design];
viewer�Viewer.CreateViewer[design, FALSE];
ViewerOps.CloseViewer[viewer]};
Initialization
CDCommandOps.RegisterWithMenu[
$SpecialMenu,
"Create Bonding Icon From Sch",
"Create layout scaled bonding icon with atomic publics",
$CreateIcPackFromSch,
CreateIcPack];
CDCommandOps.RegisterWithMenu[
$SpecialMenu,
"Create Bonding Icon From Code",
"Create layout scaled bonding icon with atomic publics",
$CreateIcPackFromCode,
CreateIcPack];
Commander.Register[key:"BuildIcPack", proc: BuildIcPackComm, doc: buildIcPackDoc];
Commander.Register[key:"GenExpertPinLists", proc: GenPinListComm, doc: genEPListsDoc];
Commander.Register[key:"GenCoordPinList",  proc: GenPinListComm, doc: genCPListsDoc];
Commander.Register[key:"GenMTSPinList",  proc: GenPinListComm, doc: genMTSPinList];
END.