DIRECTORY AlpsBool, AlpsPWGen, AlpsTile, Buttons, CD, CDAbuts, CDCells, CDDirectory, CDMenus, CDOps, CDOrient, CDPinObjects, CDProperties, CDRects, CDSequencer, CDX, CMos, CMosContacts, CMosTransistors, Commander, Convert, PWPins, RefTab, Rope, TerminalIO, ViewerClasses; AlpsPWGenImpl: CEDAR PROGRAM IMPORTS AlpsBool, AlpsTile, CDAbuts, CDCells, CDDirectory, CDOps, CDPinObjects, CDProperties, CDRects, CDX, CMos, CMosContacts, CMosTransistors, Convert, PWPins, RefTab, Rope EXPORTS AlpsPWGen = BEGIN OPEN AlpsPWGen; Tile: TYPE = AlpsTile.Tile; TileArray: TYPE = AlpsTile.TileArray; ROPE: TYPE = Rope.ROPE; Output: PROC [t1, t2, t3, t4, t5, t6: ROPE _ NIL] = AlpsBool.Output; Break: PROC [] = {}; -- Useful for context.debugging Reverse: PROC [list: LIST OF CD.ObPtr] RETURNS [newList: LIST OF CD.ObPtr _ NIL] = {WHILE list#NIL DO newList _ CONS [list.first, newList]; list _ list.rest ENDLOOP}; sizeY: INT = 48; sizeTransN: INT = 10; IncludeOb: PROC [cell, subcell: CD.ObPtr, location: CD.Position _ [0, 0], orientation: CD.Orientation _ CD.combined] RETURNS [newApp: CD.ApplicationPtr] = { newApp _ CDX.IncludeOb[ design: NIL, cell: cell, ob: subcell, position: location, orientation: orientation, cellCSystem: interrestCoords, obCSystem: interrestCoords, mode: dontPropagate ].newApp }; IncludePin: PROC [cell: CD.ObPtr, layer: CD.Layer, name: ROPE, size, pos: CD.Position] = { pinApp: CD.ApplicationPtr _ IncludeOb[cell, CDPinObjects.CreatePinOb[size], pos]; CDPinObjects.SetName[pinApp, name]; CDPinObjects.SetLayer[pinApp, layer]; }; IncludeRect: PROC [cell: CD.ObPtr, layer: CD.Layer, size, pos: CD.Position, name: ROPE _ NIL] = { appl: CD.ApplicationPtr _ IncludeOb[cell, CDRects.CreateRect[size, layer], pos]; IF name#NIL THEN CDProperties.PutPropOnApplication[onto: appl, prop: $SignalName, val: name]; }; IncludeContactPoly: PROC [cell: CD.ObPtr, pos: CD.Position] = { [] _ IncludeRect[cell, CMos.pol, [10, 10], pos]; [] _ IncludeOb[cell, CMosContacts.CreatePolyCon[8], [pos.x+1, pos.y+1]]; }; IncludeContactDiff: PROC [cell: CD.ObPtr, pos: CD.Position] = { [] _ IncludeRect[cell, CMos.ndif, [10, 10], pos]; [] _ IncludeOb[cell, CMosContacts.CreateDifCon[8], [pos.x+1, pos.y+1]]; }; IncludeContactMetal2: PROC [cell: CD.ObPtr, pos: CD.Position] = { [] _ IncludeOb[cell, CMosContacts.CreateMmCon[10], pos]; }; IncludeButtingContact: PROC [cell: CD.ObPtr, pos: CD.Position] = { [] _ IncludeOb[cell, CMosContacts.CreateButCon[], pos]; }; IncludeTransN: PROC [cell: CD.ObPtr, pos: CD.Position] = { [] _ IncludeOb[cell, CMosTransistors.CreateTransistor[sizeTransN, 4], pos, CDOrient.rotate90]; }; Reposition: PROC [cell: CD.ObPtr, 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.ObPtr] = { 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, tile.name].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]]; }; 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]]}; 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.ObPtr _ 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.ObPtr] = { columns: LIST OF CD.ObPtr _ NIL; FOR i: Columns DECREASING IN [0..tileRows.size) DO columns _ CONS[CDAbuts.CreateNewAbutY[CellsFromTiles[context, tileRows[i]]], columns]; ENDLOOP; cell _ CDAbuts.CreateNewAbutX[columns]; }; RedundancyCheck: PROC [context: AlpsTile.Context, tileRows: TilesRows] = { size: Columns _ tileRows.size; 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.ObPtr _ 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] = { posx: INT _ 0; posy: INT _ 0; size: Columns _ emptyRow.size; DO fillHappened: BOOL _ FALSE; allEmpty: BOOL _ TRUE; previousI: Columns; previousTile: Tile _ NIL; FOR i: Columns IN [0 .. size) DO FillColumn: PROC [i: Columns, tile: Tile] = { fillHappened _ TRUE; SELECT TRUE FROM tile.special => { name: ROPE _ SELECT TRUE FROM Rope.Equal[tile.name, "LatchReceive"] => "LatchNull", Rope.Equal[tile.name, "LatchSend"] => "LatchNull", Rope.Equal[tile.name, "LatchNull"] => "LatchNull", Rope.Equal[tile.name, "LatchSimple"] => "LatchNull", Rope.Equal[tile.name, "AuxReceive"] => "LatchNull", Rope.Equal[tile.name, "AuxSend"] => "LatchNull", Rope.Equal[tile.name, "CascodeVddGlue"] => "NullVddGlue", Rope.Equal[tile.name, "ThroughVddGlue"] => "NullVddGlue", Rope.Equal[tile.name, "NullVddGlue"] => "NullVddGlue", Rope.Equal[tile.name, "CascodeGndGlue"] => "NullGndGlue", Rope.Equal[tile.name, "ThroughGndGlue"] => "NullGndGlue", Rope.Equal[tile.name, "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 allEmpty _ FALSE; tile _ tileRows[i].first; 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 allEmpty THEN EXIT; RedundancyCheck[context, tileRows]; IF ~fillHappened THEN { 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; }; TileArrayToGeometry: PUBLIC PROC [context: AlpsTile.Context] RETURNS [cell: CD.ObPtr _ 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.ObPtr _ NIL; posx: INT _ 0; posy: INT _ 0; size: Columns; top, bottom, left, right: BOOL _ FALSE; contacts: CD.ObPtr; distSinceLastContacts: INT _ 0; outputNames: LIST OF ROPE _ NIL; -- 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]; 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; IF rowsOfTiles#NIL THEN { listOfContacts: LIST OF CD.ObPtr _ 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"]], Rope.Equal[thisTile.name, "BigCascodeVddGlue"] OR Rope.Equal[thisTile.name, "CascodeVddGlue"] OR Rope.Equal[thisTile.name, "ThroughVddGlue"] OR Rope.Equal[thisTile.name, "NullVddGlue"] => AlpsTile.TILE[[special: TRUE, name: "ContactVddGlue"]], Rope.Equal[thisTile.name, "CascodeGndGlue"] OR Rope.Equal[thisTile.name, "ThroughGndGlue"] OR Rope.Equal[thisTile.name, "NullGndGlue"] => AlpsTile.TILE[[special: TRUE, name: "ContactGndGlue"]], ENDCASE => AlpsTile.TILE[[special: TRUE, name: "ContactLatch"]]; listOfContacts _ CONS [CellFromTile[context, tile], listOfContacts]; ENDLOOP; contacts _ CDAbuts.CreateNewAbutX[listOfContacts]; [] _ CDDirectory.Include[context.design, contacts, "@Contacts"]; }; 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.ObPtr _ NIL; rowCellsAbut: CD.ObPtr; 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.ObPtr _ 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 _ CDAbuts.CreateNewAbutX[rowCells]; [] _ CDDirectory.Include[context.design, rowCellsAbut, "@AlpsRow"]; listOfCells _ CONS [rowCellsAbut, listOfCells]; ENDLOOP; cell _ CDAbuts.CreateNewAbutY[listOfCells]; [] _ CDDirectory.Include[context.design, cell, "@AlpsResult"]; cell _ PWPins.RenamePins[context.design, cell]; Output["Done!\n"]; END; TableToLayout: PUBLIC PROC [context: AlpsTile.Context] RETURNS [cell: CD.ObPtr] = { Output["\nLet's start Layout!"]; AlpsTile.TableAndPositionToTileArray[context]; Output["Generation of the TileArray finished\n"]; cell _ TileArrayToGeometry[context]; }; END. tAlpsPWGenImpl.mesa Created by Bertrand Serlet, March 12, 1985 2:22:19 pm PST Last edited by Serlet July 11, 1985 1:12:17 am PDT Last Edited by: Sindhu, June 17, 1985 10:15:38 pm PDT Utilities Always useful ... Geometry generation Does NOT include in directory We can always put those contacts to Gnd when gndTrans The metal2 and the connection to Gnd is justy a bonus Some redundancy check FOR i: Columns IN [0 .. size) DO upDownMetal: INT _ IF 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.ObPtr _ MakeCellInCaseOfError[context, tileRows]; CDOps.AddAnObject[context.design, cell, [0, 0]]; Output["Mismatch of pins in column ", Convert.RopeFromInt[i]]; ERROR; }; ENDLOOP; ATTENTION, rowsOfTiles is from top to bottom Output["*"]; Output[" ", Convert.RopeFromInt[i]]; copy bottom row Modifies the array of cells for adding all cells due to the insert of an expr. We find which Route columns can be contracted into 4 lambdas wide filler Generation of the contacts cell Generation of the abuts in X Just in case, the AbutX won't work, we add them in the context.design posx _ posy _ 0; FOR list: LIST OF CD.ObPtr _ 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 This one is the only one clients have to know Ê…˜™J™9J™2—J™5J™šÏk ˜ Jšœ˜Jšœ˜ Jšœr˜tJšœ%˜%Jšœ˜Jšœ˜Jšœ(˜(—J˜•StartOfExpansion[]šœœ˜Jšœ`œE˜¯Jšœ ˜J˜Jš˜Jšœ ˜J˜JšÏbœœ˜Jšž œœ˜%J™™ J™Jšœœœ˜JšÏnœœœœ˜D—J˜JšŸœœ Ïc˜4J˜Jšœ™šŸœœœœœœ œœœ œ˜RJš œœœœ œ)œ˜S—J˜J˜J™J™Jšžœœ˜Jšž œœ˜J™šŸ œœœœ!œœ œ œ˜œšœ œ ˜JšœœI˜TJšœM˜MJšœ˜—Jšœ˜—J˜š Ÿ œœœœœ œ˜ZJšœœG˜QJšœJ˜JJ˜—J™šŸ œœœœœœœ˜aJšœœH˜PJšœœœM˜]J˜—J˜šŸœœœ œ˜?Jšœ0˜0JšœH˜HJ˜—J˜šŸœœœ œ˜?Jšœ1˜1JšœG˜GJ˜—J˜šŸœœœ œ˜AJšœ8˜8J˜—J˜šŸœœœ œ˜BJšœ7˜7J˜—J˜šŸ œœœ œ˜:Jšœ^˜^J˜—J˜Jšœ™šŸ œœœœ˜1Jš œœœœœ]˜–Jšœ4˜4Jšœ"œ˜(J˜—J˜J˜š Ÿ œœœ)œœ ˜^Jšœœ˜Jšœ9˜9šœœ˜Jšœ œœ˜šœ˜Jšœ;˜;Jš œœœœ ˜(J˜—šœ˜Jšœ!˜!Jšœœœœ/˜lJšœœœœ0˜nJšœ›˜›Jšœ œœœ.˜jJšœ œœœ.˜kJ˜Jšœœœ œ#˜aJšœœœ œ'˜hJšœœœ œ˜[Jšœœœ œ!˜bJšœ0˜0Jšœ1˜1J™šœœœ œ˜Jšœ*˜*šœ#œ˜@Jšœ#œœ˜LJšœ˜—Jšœ˜—Jšœ>˜>Jšœ œ"œ˜Cšœœ$˜>šœ#œ˜@šœ#œœ˜0Jšœ1˜1šœœ˜šœ ˜Jšœœ œœœœ œ œ˜‡Jš œœ œ œ œ˜NJšœœ œ œ˜>Jš œœœ œœ œ˜kJšœœ˜2Jšœœ˜——Jšœ ˜ Jšœ˜—Jšœ˜—Jšœ˜—Jšœ œœ˜Jšœ#˜#Jšœ˜—J˜šŸœœ2œœ ˜iJš œ œœœ œ˜ šœ œœ˜2Jšœ œH˜VJšœ˜—Jšœ'˜'J˜J˜J˜—šŸœœ5˜JJšœ™Jšœ˜šœ œ ™ Jš œ œœ œœœœ™Tš œœœœœ™AJšœ™Jšœœ™3Jšœœ™5Jšœ™—šœœ™Jšœœ2™:Jšœ0™0Jšœ?™EJšœ™—Jšœ™—šœ œ ˜ Jšœœ˜š œœœ!œœ˜CJšœ˜Jšœœ˜0Jšœ˜—š œœœœœ˜AJšœ˜Jšœœ˜-Jšœ˜—šœœ˜Jšœœ2˜:Jšœ0˜0Jšœaœ˜gJšœ˜—Jšœ˜—J˜—J˜š ŸœœAœœœœ˜ˆJšœ,™,Jšœœ œ˜Jšœ˜š˜Jš œœœ œœ˜3Jšœ)œ˜.šœ œ ˜ šŸ œœ˜-Jšœ ™ Jšœœ˜šœœ˜šœ˜šœœœœ˜Jšœ9˜9Jšœ7˜7Jšœ7˜7Jšœ9˜9J˜Jšœ8˜8Jšœ6˜6J˜Jšœ<˜˜>Jšœ˜—Jšœœ˜)J˜—Jšœ˜—J˜—J˜J™Oš Ÿœœœœœ œ˜]Jš˜Jšœœ˜!Jšœœœ œœœœ ˜kJšœ˜Jšœ˜Jšœ œœœ ˜5Jš œ œœœ œ˜$Jšœœ œ˜Jšœ˜Jšœœœ˜'Jšœ œ˜Jšœœ˜Jš œ œœœœ "˜CJ˜š œœœ7œœ˜YJšœœ˜Jš œœœœœ˜JJšœ˜—J˜Jšœ) !˜JJšœ5˜5Jšœ˜JšœA˜AJ˜J™IJšœœ˜)Jš œ œ œœœ˜Aš œœœœœ˜@šœ œ ˜ Jšœ$˜$Jš œ œœœœ˜TJšœ˜—Jšœ˜—Jš œ œ œœœ œ˜NJ˜J™šœ œœ˜Jš œœœœ œ˜'Jšœ!˜!šœ œœ ˜+Jšœ%˜%šœœœ˜&Jšœœ œ˜KJšœœ œ˜IJšœœ œ˜HJš œ/œ-œ-œ7œ œ˜õJš œ,œ-œ8œ œ˜ÃJšœœ œ˜A—Jšœœ/˜DJšœ˜—Jšœ2˜2Jšœ@˜@J˜—J™Jšœ™J˜%J˜š œœœ*œœ˜dJšœ&˜&Jš œ œœœ œ˜!Jšœœ˜Jšœœ '˜TJšœCœ˜Gšœ œœ ˜+šžœÐck.œ˜Lšœœ˜šœœœ#˜6Jšœ˜Jšœ˜J˜—šœœœ'˜:Jšœ.˜.Jšœ˜J˜—šœœœ&˜9Jšœ-˜-Jšœ˜J˜—šœœœ*˜=Jšœ5˜5Jšœ˜J˜—šœœ œ#˜6Jšœ œœœ˜-Jšœ˜Jšœ0˜0Jšœ˜—šœœ œ%˜8Jšœ œœœ˜,Jšœ˜Jšœ:˜:Jšœ˜—šœœ œ'˜:Jšœ œœœ˜-Jšœ˜Jšœ8˜8Jšœ˜—šœœ œ)˜˜>Jšœ/˜/J˜Jšœ˜—J™Jšœ-™-šŸ œ œœœ ˜SJ˜ Jšœ.˜.J˜1Jšœ$˜$J˜—J˜Jšœ˜——…—E~`w