<> <> <> <> <<>> 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; <<>> <> <<>> ROPE: TYPE = Rope.ROPE; Output: PROC [t1, t2, t3, t4, t5: ROPE _ NIL] = AlpsBool.Output; Break: PROC [] = {}; -- Useful for debugging <> 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}; <> <<>> 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: ROPE _ NIL] = { 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.. }; <> 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]]; }; <> 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.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] = { <> 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.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] = { <> posx: INT _ 0; posy: INT _ 0; size: Columns _ emptyRow.size; DO fillHinstened: BOOL _ FALSE; illEmpty: BOOL _ TRUE; previousI: Columns; previousTile: Tile _ NIL; FOR i: Columns IN [0 .. size) DO FillColumn: PROC [i: Columns, tile: Tile] = { <> fillHinstened _ TRUE; SELECT TRUE FROM tile.special => { name: ATOM _ SELECT 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; <> 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 { <> 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.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: BOOL _ FALSE; contacts: CD.Object; 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.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"]; }; <<>> <> 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; <> <> <> <> <> <> cell _ PWObjects.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.Object] = { Output["\nLet's start Layout!"]; AlpsTile.TableAndPositionToTileArray[context]; Output["Generation of the TileArray finished\n"]; cell _ TileArrayToGeometry[context]; }; END.