AlpsPWGenImpl.mesa
Created by Bertrand Serlet, October 23, 1985 4:48:35 pm PDT
Last edited by Serlet July 11, 1985 1:12:17 am PDT
Last Edited by: Sindhu, June 17, 1985 10:15:38 pm PDT
DIRECTORY
AlpsBool, AlpsPWGen, AlpsTile,
CD, CDCells, CDDirectory, CDMenus, CDOps, CDOrient, CDPinObjects, CDProperties, CDRects, CDSimpleRules, CDSequencer,
CMos, CMosObjects,
Commander, Convert,
PWObjects, PWPins,
RefTab, Rope, TerminalIO, ViewerClasses;
AlpsPWGenImpl: CEDAR PROGRAM
IMPORTS AlpsBool, AlpsTile, CDCells, CDDirectory, CDOps, CDPinObjects, CDProperties, CDRects, CDSimpleRules, CMos, CMosObjects, Convert, PWObjects, PWPins, RefTab, Rope
EXPORTS AlpsPWGen =
BEGIN
OPEN AlpsPWGen;
Tile: TYPE = AlpsTile.Tile;
TileArray: TYPE = AlpsTile.TileArray;
Utilities
ROPE: TYPE = Rope.ROPE;
Output: PROC [t1, t2, t3, t4, t5: ROPENIL] = AlpsBool.Output;
Break: PROC [] = {}; -- Useful for debugging
Always useful ...
Reverse: PROC [list: LIST OF CD.Object] RETURNS [newList: LIST OF CD.Object ← NIL] =
{WHILE list#NIL DO newList ← CONS [list.first, newList]; list ← list.rest ENDLOOP};
Geometry generation
sizeY: INT = 48;
sizeTransN: INT = 10;
IncludeOb: PROC [cell, subcell: CD.Object, location: CD.Position ← [0, 0], orientation: CD.Orientation ← CD.combined] RETURNS [newInst: CD.Instance] = {
newInst ← CDCells.IncludeOb[
design: NIL, cell: cell, ob: subcell, position: location, orientation: orientation,
cellCSystem: interrestCoords, obCSystem: interrestCoords, mode: dontPropagate
].newInst
};
IncludePin: PROC [cell: CD.Object, layer: CD.Layer, name: ROPE, size, pos: CD.Position] = {
pinInstance: CD.Instance ← IncludeOb[cell, CDPinObjects.CreatePinOb[size], pos];
CDPinObjects.SetName[pinInstance, name]; CDPinObjects.SetLayer[pinInstance, layer];
};
IncludeRect: PROC [cell: CD.Object, layer: CD.Layer, size, pos: CD.Position, name: ROPENIL] = {
instl: CD.Instance ← IncludeOb[cell, CDRects.CreateRect[size, layer], pos];
IF name#NIL THEN CDProperties.PutPropOnInstance[onto: instl, prop: $SignalName, val: name];
};
IncludeContactPoly: PROC [cell: CD.Object, pos: CD.Position] = {
[] ← IncludeRect[cell, CMos.pol, [10, 10], pos];
[] ← IncludeOb[cell, CDSimpleRules.Contact[CMos.pol, CMos.met], [pos.x+1, pos.y+1]];
};
IncludeContactDiff: PROC [cell: CD.Object, pos: CD.Position] = {
[] ← IncludeRect[cell, CMos.ndif, [10, 10], pos];
[] ← IncludeOb[cell, CDSimpleRules.Contact[CMos.ndif, CMos.met], [pos.x+1, pos.y+1]];
};
IncludeContactMetal2: PROC [cell: CD.Object, pos: CD.Position] = {
[] ← IncludeOb[cell, CDSimpleRules.Contact[CMos.met2, CMos.met], pos];
};
IncludeTransN: PROC [cell: CD.Object, pos: CD.Position] = {
[] ← IncludeOb[cell, CMosObjects.CreateTransistor[[8+sizeTransN, 8+4], CMos.ndif], pos, CDOrient.rotate90]; -- these numeric arguments are just stupid..
};
Does NOT include in directory
Reposition: PROC [cell: CD.Object, sizeX: INT] = {
IF NARROW[cell.specificRef, CD.CellPtr].contents=NIL THEN IncludePin[cell, CMos.met2, "JustForAvoidingEmptyCell", [4, 4], [(sizeX-4)/2, (sizeY-4)/2]];
CDCells.SetInterestRect[cell, [0, 0, sizeX, sizeY]];
[] ← CDCells.RepositionCell[cell, NIL];
};
CellFromTile: PUBLIC PROC [context: AlpsTile.Context, tile: Tile] RETURNS [cell: CD.Object] = {
found: BOOL; val: RefTab.Val;
[found, val] ← RefTab.Fetch[context.computedCells, tile];
SELECT TRUE FROM
found   => RETURN[NARROW[val]];
tile.special => {
cell ← CDDirectory.Fetch[context.design, Convert.RopeFromAtom[tile.name, FALSE]].object;
IF cell=NIL THEN ERROR; -- cell missing!
};
tile.input  => {
cell ← CDCells.CreateEmptyCell[];
IF (~(tile.high AND tile.throughTrans) AND tile.leftPin) THEN IncludeRect[cell, CMos.met, [14, 6], [0, 36]];
IF (~(tile.high AND tile.throughTrans) AND tile.rightPin) THEN IncludeRect[cell, CMos.met, [14, 6], [4 , 36]];
IncludeRect[cell, CMos.met, [18, 12], [0, 18]]; IncludePin[cell, CMos.met, "Gnd", [4, 12], [0, 18]]; IncludePin[cell, CMos.met, "Gnd", [4, 12], [14, 18]];
IF (~(tile.low AND tile.throughTrans) AND tile.leftPin) THEN IncludeRect[cell, CMos.met, [14, 6], [0, 6]];
IF (~(tile.low AND tile.throughTrans) AND tile.rightPin) THEN IncludeRect[cell, CMos.met, [14, 6], [4, 6]];
IncludePin[cell, CMos.met2, IF tile.leftSide THEN "Input" ELSE "NotInput", [8, 4], [5, sizeY-4]];
IncludePin[cell, CMos.pol, IF tile.leftSide THEN "InputPoly" ELSE "NotInputPoly", [4, 4], [7, sizeY-4]];
IncludePin[cell, CMos.met2, IF tile.leftSide THEN "Input" ELSE "NotInput", [8, 4], [5, 0]];
IncludePin[cell, CMos.pol, IF tile.leftSide THEN "InputPoly" ELSE "NotInputPoly", [4, 4], [7, 0]];
IncludeRect[cell, CMos.pol, [4, sizeY], [7, 0]];
IncludeRect[cell, CMos.met2, [8, sizeY], [5, 0]];
IF (tile.throughTrans OR tile.gndTrans) AND tile.high THEN {
IncludeTransN[cell, [3, 31]];
IncludeContactDiff[cell, [IF tile.leftSide THEN -5 ELSE 13, 35]];
IF tile.throughTrans THEN IncludeContactDiff[cell, [IF tile.leftSide THEN 13 ELSE -5, 35]] ELSE IncludeRect[cell, CMos.ndif, [10, 18], [IF tile.leftSide THEN 13 ELSE -5, 27]];
};
IF (tile.throughTrans OR tile.gndTrans) AND tile.low THEN {
IncludeTransN[cell, [3, -1]];
IncludeContactDiff[cell, [IF tile.leftSide THEN -5 ELSE 13, 3]];
IF tile.throughTrans THEN IncludeContactDiff[cell, [IF tile.leftSide THEN 13 ELSE -5, 3]] ELSE IncludeRect[cell, CMos.ndif, [10, 18], [IF tile.leftSide THEN 13 ELSE -5, 3]];
};
We can always put those contacts to Gnd when gndTrans
IF tile.gndTrans THEN IncludeContactDiff[cell, [IF tile.leftSide THEN 13 ELSE -5, 19]];
IF tile.contact AND tile.high THEN IncludeContactPoly[cell, [5, 35]];
IF tile.contact AND tile.low THEN IncludeContactPoly[cell, [5, 3]];
Reposition[cell, 18];
[] ← CDDirectory.Include[context.design, cell, "@AlpsInputTile"];
};
tile.route  => {
sizeX: INT = 36;
cell ← CDCells.CreateEmptyCell[];
IF ~tile.noLeftMetal THEN IncludeRect[cell, CMos.met, [25, 6], [0, 36]];
IF ~tile.noRightMetal THEN IncludeRect[cell, CMos.met, [25, 6], [11, 36]];
IncludeRect[cell, CMos.met, [sizeX, 12], [0, 18]]; IncludePin[cell, CMos.met, "Gnd", [4, 12], [0, 18]]; IncludePin[cell, CMos.met, "Gnd", [4, 12], [sizeX-4 , 18]];
IF ~tile.noLeftMetal THEN IncludeRect[cell, CMos.met, [25, 6], [0, 6]];
IF ~tile.noRightMetal THEN IncludeRect[cell, CMos.met, [25, 6], [11, 6]];
IF ~tile.noUpPoly THEN {IncludeRect[cell, CMos.pol, [4, sizeY-6], [7, 6]]; IncludeRect[cell, CMos.pol, [4, sizeY-6], [25, 6]]};
IF ~tile.noDownPoly THEN {IncludeRect[cell, CMos.pol, [4, sizeY-6], [7, 0]]; IncludeRect[cell, CMos.pol, [4, sizeY-6], [25, 0]]};
The metal2 and the connection to Gnd is justy a bonus
IncludePin[cell, CMos.met2, "Gnd", [22, 4], [7, 0]];
IncludePin[cell, CMos.met2, "Gnd", [22, 4], [7, sizeY-4]];
IncludeRect[cell, CMos.met2, [22, sizeY], [7, 0]];
IncludeContactMetal2[cell, [13, 19]];
IF tile.contactPoly THEN {IncludeContactPoly[cell, [7, IF tile.spin THEN 35 ELSE 3]]; IncludeContactPoly[cell, [19, IF tile.spin THEN 3 ELSE 35]]};
Reposition[cell, sizeX];
[] ← CDDirectory.Include[context.design, cell, "@AlpsRouteTile"];
};
ENDCASE  => ERROR;
[] ← RefTab.Store[context.computedCells, tile, cell];
IF cell=NIL THEN ERROR;
};
CellsFromTiles: PUBLIC PROC [context: AlpsTile.Context, tiles: LIST OF Tile] RETURNS [cells: LIST OF CD.Object ← NIL] = {
WHILE tiles#NIL DO
cells ← CONS [CellFromTile[context, tiles.first], cells]; tiles ← tiles.rest ENDLOOP;
cells ← Reverse[cells];
};
Columns: TYPE = [0 .. 1000]; -- ?!?!?!
TilesRows: TYPE = REF TilesRowsRec;
TilesRowsRec: TYPE = RECORD [
contents: SEQUENCE size: Columns OF LIST OF Tile]; -- from left to right
Row: TYPE = REF RowRec;
RowRec: TYPE = RECORD [
contents: SEQUENCE size: Columns OF Tile]; -- from left to right, from LeftVdd to Self
TileArrayToTilesRows: PROC [context: AlpsTile.Context] RETURNS [tileRows: TilesRows, emptyRow: Row, nullRouteRow: Row] = {
size, nb: Columns ← 0;
FOR i: AlpsBool.VarNb IN [0 .. context.tileArray.lastPosNb) DO
Output[" ", Convert.RopeFromInt[i], ": "];
FOR horTileType: AlpsTile.HorTileType IN AlpsTile.HorTileType DO
IF context.tileArray[i][horTileType]#NIL THEN {size ← size+1; Output["."]};
ENDLOOP;
ENDLOOP;
Output["\n", Convert.RopeFromInt[size], " useful columns.\n"];
tileRows ← NEW [TilesRowsRec[size]]; emptyRow ← NEW [RowRec[size]];
FOR i: AlpsBool.VarNb IN [0 .. context.tileArray.lastPosNb) DO
FOR horTileType: AlpsTile.HorTileType IN AlpsTile.HorTileType DO
IF context.tileArray[i][horTileType]#NIL THEN {
tileRows[nb] ← context.tileArray[i][horTileType];
emptyRow[nb] ← AlpsTile.TILE[
SELECT horTileType FROM
RightRoute  => [route: TRUE, noUpPoly: TRUE, noDownPoly: TRUE, noLeftMetal: TRUE, noRightMetal: TRUE, leftPin: FALSE, rightPin: FALSE],
LeftInput   => [input: TRUE, leftSide: TRUE, leftPin: FALSE, rightPin: FALSE],
RightInput  => [input: TRUE, leftPin: FALSE, rightPin: FALSE],
VddGlue   => [special: TRUE, name: IF nb=size-1 AND context.isLatched THEN $LatchNull ELSE $NullVddGlue],
GndGlue   => [special: TRUE, name: $NullGndGlue],
ENDCASE   => ERROR];
nb ← nb + 1;
};
ENDLOOP;
ENDLOOP;
IF nb#size THEN ERROR;
RedundancyCheck[context, tileRows];
};
MakeCellInCaseOfError: PROC [context: AlpsTile.Context, tileRows: TilesRows] RETURNS [cell: CD.Object] = {
columns: LIST OF CD.Object ← NIL;
FOR i: Columns DECREASING IN [0..tileRows.size) DO
columns ← CONS[PWObjects.CreateNewAbutY[CellsFromTiles[context, tileRows[i]]], columns];
ENDLOOP;
cell ← PWObjects.CreateNewAbutX[columns];
};
RedundancyCheck: PROC [context: AlpsTile.Context, tileRows: TilesRows] = {
Some redundancy check
size: Columns ← tileRows.size;
FOR i: Columns IN [0 .. size) DO
upDownMetal: INTIF tileRows[i]#NIL AND tileRows[i].first.downMetal THEN 1 ELSE 0;
FOR list: LIST OF Tile ← tileRows[i], list.rest WHILE list#NIL DO
tile: Tile ← list.first;
IF tile.upMetal THEN upDownMetal ← upDownMetal + 1;
IF tile.downMetal THEN upDownMetal ← upDownMetal - 1;
ENDLOOP;
IF upDownMetal#0 THEN {
cell: CD.Object ← MakeCellInCaseOfError[context, tileRows];
CDOps.AddAnObject[context.design, cell, [0, 0]];
Output["Mismatch of pins in column ", Convert.RopeFromInt[i]]; ERROR;
};
ENDLOOP;
FOR i: Columns IN (0 .. size) DO
leftPins, rightPins: INT ← 0;
FOR list: LIST OF Tile ← tileRows[i-1], list.rest WHILE list#NIL DO
tile: Tile ← list.first;
IF tile.rightPin THEN rightPins ← rightPins + 1;
ENDLOOP;
FOR list: LIST OF Tile ← tileRows[i], list.rest WHILE list#NIL DO
tile: Tile ← list.first;
IF tile.leftPin THEN leftPins ← leftPins + 1;
ENDLOOP;
IF leftPins#rightPins THEN {
cell: CD.Object ← MakeCellInCaseOfError[context, tileRows];
CDOps.AddAnObject[context.design, cell, [0, 0]];
Output["Mismatch of pins between columns right ", Convert.RopeFromInt[i-1], " and next left\n"]; ERROR;
};
ENDLOOP;
};
TilesRowsToListOfRows: PROC [context: AlpsTile.Context, tileRows: TilesRows, emptyRow: Row] RETURNS [rowsOfTiles: LIST OF Row ← NIL] = {
ATTENTION, rowsOfTiles is from top to bottom
posx: INT ← 0; posy: INT ← 0;
size: Columns ← emptyRow.size;
DO
fillHinstened: BOOLFALSE; illEmpty: BOOLTRUE;
previousI: Columns; previousTile: Tile ← NIL;
FOR i: Columns IN [0 .. size) DO
FillColumn: PROC [i: Columns, tile: Tile] = {
Output["*"];
fillHinstened ← TRUE;
SELECT TRUE FROM
tile.special  => {
name: ATOMSELECT tile.name FROM
$LatchReceive     => $LatchNull,
$LatchSend      => $LatchNull,
$LatchNull      => $LatchNull,
$LatchSimple     => $LatchNull,
$AuxReceive      => $LatchNull,
$AuxSend       => $LatchNull,
$CascodeVddGlue    => $NullVddGlue,
$ThroughVddGlue    => $NullVddGlue,
$NullVddGlue     => $NullVddGlue,
$CascodeGndGlue    => $NullGndGlue,
$ThroughGndGlue    => $NullGndGlue,
$NullGndGlue     => $NullGndGlue,
ENDCASE       => ERROR;
tileRows[i] ← CONS [AlpsTile.TILE[[special: TRUE, name: name]], tileRows[i]];
};
tile.input  => {
tileRows[i] ← CONS [AlpsTile.TILE[[input: TRUE, leftSide: tile.leftSide, leftPin: FALSE, rightPin: FALSE]], tileRows[i]];
};
tile.route  => {
tileRows[i] ← CONS [AlpsTile.TILE[[route: TRUE, noUpPoly: tile.noDownPoly, noDownPoly: tile.noDownPoly, noLeftMetal: TRUE, noRightMetal: TRUE, leftPin: FALSE, rightPin: FALSE]], tileRows[i]];
};
ENDCASE  => ERROR;
};
tile: Tile;
IF tileRows[i]=NIL
THEN tileRows[i] ← LIST[emptyRow[i]]
ELSE illEmpty ← FALSE;
tile ← tileRows[i].first;
Output[" ", Convert.RopeFromInt[i]];
IF previousTile#NIL AND ~previousTile.rightPin AND tile.leftPin
THEN {FillColumn[i, tile]; tile ← tileRows[i].first};
IF previousTile#NIL AND previousTile.rightPin AND ~tile.leftPin
THEN FillColumn[previousI, previousTile];
previousI ← i; previousTile ← tile;
ENDLOOP;
IF illEmpty THEN EXIT;
RedundancyCheck[context, tileRows];
IF ~fillHinstened THEN {
copy bottom row
newRow: Row ← NEW [RowRec[size]];
Output["|"];
FOR i: Columns IN [0 .. size) DO
newRow[i] ← tileRows[i].first; tileRows[i] ← tileRows[i].rest;
ENDLOOP;
rowsOfTiles ← CONS [newRow, rowsOfTiles];
};
ENDLOOP;
};
Modifies the array of cells for adding ill cells due to the insert of an expr.
TileArrayToGeometry: PUBLIC PROC [context: AlpsTile.Context] RETURNS [cell: CD.Object ← NIL] =
BEGIN
shortRouteRow: REF RouteRowBools;
RouteRowBools: TYPE = RECORD [contents: PACKED SEQUENCE size: Columns OF BOOL]; -- TRUE means a short Route
tileRows: TilesRows;
emptyRow: Row;
rowsOfTiles: LIST OF Row ← NIL; -- from top to bottom
listOfCells: LIST OF CD.Object ← NIL;
posx: INT ← 0; posy: INT ← 0;
size: Columns;
top, bottom, left, right: BOOLFALSE;
contacts: CD.Object;
distSinceLastContacts: INT ← 0;
outputNames: LIST OF ROPENIL; -- a times the name of each output
FOR outs: LIST OF AlpsBool.OutputRef ← context.table.outputs, outs.rest WHILE outs#NIL DO
name: ROPE ← outs.first.name;
outputNames ← CONS[name, CONS[name, CONS[name, CONS[name, outputNames]]]];
ENDLOOP;
context.computedCells ← RefTab.Create[]; -- for remembering computed cells
[tileRows, emptyRow] ← TileArrayToTilesRows[context];
size ← emptyRow.size;
rowsOfTiles ← TilesRowsToListOfRows[context, tileRows, emptyRow];
We find which Route columns can be contracted into 4 lambdas wide filler
shortRouteRow ← NEW[RouteRowBools[size]];
FOR i: Columns IN [0 .. size) DO shortRouteRow[i] ← TRUE ENDLOOP;
FOR rows: LIST OF Row ← rowsOfTiles, rows.rest WHILE rows#NIL DO
FOR i: Columns IN [0 .. size) DO
tile: AlpsTile.Tile ← rows.first[i];
IF ~tile.route OR ~tile.noDownPoly OR ~tile.noUpPoly THEN shortRouteRow[i] ← FALSE;
ENDLOOP;
ENDLOOP;
FOR i: Columns IN [0 .. size) DO IF shortRouteRow[i] THEN Output["$"] ENDLOOP;
Generation of the contacts cell
IF rowsOfTiles#NIL THEN {
listOfContacts: LIST OF CD.Object ← NIL;
thisRow: Row ← rowsOfTiles.first;
FOR i: Columns DECREASING IN [0 .. size) DO
thisTile: AlpsTile.Tile ← thisRow[i];
tile: AlpsTile.Tile ← SELECT TRUE FROM
shortRouteRow[i]  => AlpsTile.TILE[[special: TRUE, name: $ContactFiller]],
thisTile.route   => AlpsTile.TILE[[special: TRUE, name: $ContactRoute]],
thisTile.input  => AlpsTile.TILE[[special: TRUE, name: $ContactInput]],
thisTile.name=$BigCascodeVddGlue OR thisTile.name=$CascodeVddGlue OR thisTile.name=$ThroughVddGlue OR thisTile.name = $NullVddGlue  => AlpsTile.TILE[[special: TRUE, name: $ContactVddGlue]],
thisTile.name=$CascodeGndGlue OR thisTile.name=$ThroughGndGlue OR thisTile.name=$NullGndGlue   => AlpsTile.TILE[[special: TRUE, name: $ContactGndGlue]],
ENDCASE  => AlpsTile.TILE[[special: TRUE, name: $ContactLatch]];
listOfContacts ← CONS [CellFromTile[context, tile], listOfContacts];
ENDLOOP;
contacts ← PWObjects.CreateNewAbutX[listOfContacts];
[] ← CDDirectory.Include[context.design, contacts, "@Contacts"];
};
Generation of the abuts in X
Output["\nGeneration of Abuts...\n"];
FOR theseRowsOfTiles: LIST OF Row ← rowsOfTiles, theseRowsOfTiles.rest WHILE theseRowsOfTiles#NIL DO
thisRow: Row ← theseRowsOfTiles.first;
rowCells: LIST OF CD.Object ← NIL;
rowCellsAbut: CD.Object;
index, notIndex: INT ← context.table.size*4; -- hack because 4 pins of each name ...
top ← theseRowsOfTiles=rowsOfTiles; bottom ← theseRowsOfTiles.rest=NIL;
FOR i: Columns DECREASING IN [0 .. size) DO
Rename: PWPins.RenameProc -- [oldRope: ROPE] RETURNS [newRope: ROPE] -- = {
SELECT TRUE FROM
(right OR left) AND Rope.Equal[oldRope, "Output"] => {
newRope ← outputNames.first;
outputNames ← outputNames.rest;
};
(right OR left) AND Rope.Equal[oldRope, "OutputPoly"] => {
newRope ← Rope.Cat[outputNames.first, "Poly"];
outputNames ← outputNames.rest;
};
(right OR left) AND Rope.Equal[oldRope, "NotOutput"] => {
newRope ← Rope.Cat["Not", outputNames.first];
outputNames ← outputNames.rest;
};
(right OR left) AND Rope.Equal[oldRope, "NotOutputPoly"] => {
newRope ← Rope.Cat["Not", outputNames.first, "Poly"];
outputNames ← outputNames.rest;
};
(top OR bottom) AND Rope.Equal[oldRope, "Input"]  => {
IF ~tile.input OR ~tile.leftSide THEN ERROR;
index ← index-1;
newRope ← Rope.Cat[context.table[index/4].name];
};
(top OR bottom) AND Rope.Equal[oldRope, "NotInput"] => {
IF ~tile.input OR tile.leftSide THEN ERROR;
notIndex ← notIndex-1;
newRope ← Rope.Cat["Not", context.table[notIndex/4].name];
};
(top OR bottom) AND Rope.Equal[oldRope, "InputPoly"]  => {
IF ~tile.input OR ~tile.leftSide THEN ERROR;
index ← index-1;
newRope ← Rope.Cat[context.table[index/4].name, "Poly"];
};
(top OR bottom) AND Rope.Equal[oldRope, "NotInputPoly"] => {
IF ~tile.input OR tile.leftSide THEN ERROR;
notIndex ← notIndex-1;
newRope ← Rope.Cat["Not", context.table[notIndex/4].name, "Poly"];
};
ENDCASE              => newRope ← oldRope;
};
tile: AlpsTile.Tile ← IF shortRouteRow[i]
THEN AlpsTile.TILE[[special: TRUE, name: IF thisRow[i].noLeftMetal THEN $EmptyRouteFiller ELSE $RouteFiller]]
ELSE thisRow[i];
thisCell: CD.Object ← CellFromTile[context, tile];
left ← i=0; right ← i=size-1;
IF left OR right OR top OR bottom
THEN thisCell ← PWPins.RenamePins[context.design, thisCell, Rename];
IF ABS [index - notIndex] > 4 THEN ERROR;
rowCells ← CONS [thisCell, rowCells];
ENDLOOP;
IF distSinceLastContacts>=context.distanceBetweenContacts THEN {
distSinceLastContacts ← 0;
listOfCells ← CONS [contacts, listOfCells];
} ELSE distSinceLastContacts ← distSinceLastContacts+1;
rowCellsAbut ← PWObjects.CreateNewAbutX[rowCells];
[] ← CDDirectory.Include[context.design, rowCellsAbut, "@AlpsRow"];
listOfCells ← CONS [rowCellsAbut, listOfCells];
ENDLOOP;
Just in case, the AbutX won't work, we add them in the context.design
posx ← posy ← 0;
FOR list: LIST OF CD.Object ← listOfCells, list.rest WHILE list#NIL DO
CDOps.AddAnObject[context.design, list.first, [posx, posy]]; posy ← posy + CD.InterestRect[list.first].y2;
ENDLOOP;
We compute the AbutY, at least, and grasp the top level pins
cell ← PWObjects.CreateNewAbutY[listOfCells];
[] ← CDDirectory.Include[context.design, cell, "@AlpsResult"];
cell ← PWPins.RenamePins[context.design, cell];
Output["Done!\n"];
END;
This one is the only one clients have to know
TableToLayout: PUBLIC PROC [context: AlpsTile.Context] RETURNS [cell: CD.Object] = {
Output["\nLet's start Layout!"];
AlpsTile.TableAndPositionToTileArray[context];
Output["Generation of the TileArray finished\n"];
cell ← TileArrayToGeometry[context];
};
END.