DIRECTORY CD, CDCells, CDSimpleRules, CDSymbolicObjects, CedarProcess, CoreClasses, CoreOps, CoreProperties, CoreGeometry, IO, PW, PWCore, PWCoreRoute, PWRoute, Rope, Route, Sisyph; PWCoreRouteImpl: CEDAR PROGRAM IMPORTS CD, CDCells, CDSimpleRules, CDSymbolicObjects, CedarProcess, CoreClasses, CoreOps, CoreProperties, CoreGeometry, IO, PW, PWCore, PWRoute, Rope, Route, Sisyph EXPORTS PWCoreRoute = BEGIN OPEN PWCoreRoute; technologyKey: PUBLIC ATOM _ $cmosB; GndAndVdd25Met2MinWidth: PUBLIC PWRoute.WireWidthProc = { wireWidth _ CDSimpleRules.MinWidth[CDSimpleRules.GetLayer[technologyKey, "metal2"]] *(IF Rope.Equal[netName, "Vdd"] OR Rope.Equal[netName, "Gnd"] THEN 25 ELSE 1); }; Channel: PUBLIC PWCore.LayoutProc = { data: CoreClasses.RecordCellType; leftOrBottomCT, rightOrTopCT: CellType; leftOrBottom, rightOrTop: CD.Object; obj1, obj2, bottomOrLeftObj, topOrRightObj, channel, extended1, extended2: PW.Object; params: PWRoute.RouterParams; channelData: ChannelData; inX: BOOL; leftOrBottomHeight, rightOrTopHeight, leftOrBottomExtend, rightOrTopExtend: INT; trLayer, brLayer: CD.Layer; priority: CedarProcess.Priority; channelData _ NARROW [CoreProperties.GetCellTypeProp[cellType, $ChannelData]]; inX _ channelData.inX; data _ NARROW [cellType.data]; IF data.size#2 THEN ERROR; leftOrBottomCT _ data[0].type; rightOrTopCT _ data[1].type; leftOrBottom _ PWCore.Layout[leftOrBottomCT]; rightOrTop _ PWCore.Layout[rightOrTopCT]; leftOrBottomHeight _ IF inX THEN CD.InterestSize[leftOrBottom].y ELSE CD.InterestSize[leftOrBottom].x; rightOrTopHeight _ IF inX THEN CD.InterestSize[rightOrTop].y ELSE CD.InterestSize[rightOrTop].x; leftOrBottomExtend _ IF channelData.extend THEN MAX[leftOrBottomHeight, rightOrTopHeight] - leftOrBottomHeight ELSE 0; rightOrTopExtend _ IF channelData.extend THEN MAX[leftOrBottomHeight, rightOrTopHeight] - rightOrTopHeight ELSE 0; trLayer _ CDSimpleRules.GetLayer[technologyKey, channelData.trunkLayer]; brLayer _ CDSimpleRules.GetLayer[technologyKey, channelData.branchLayer]; priority _ CedarProcess.GetPriority[]; extended1 _ Filler[leftOrBottomCT, inX, trLayer, leftOrBottomExtend, channelData.extendTopOrRight]; extended2 _ Filler[rightOrTopCT, inX, trLayer, rightOrTopExtend, channelData.extendTopOrRight]; obj1 _ MakeOutline[data[0], data.internal, IF inX THEN right ELSE top, brLayer, CD.InterestSize[extended1], IF channelData.extendTopOrRight THEN 0 ELSE leftOrBottomExtend]; obj2 _ MakeOutline[data[1], data.internal, IF inX THEN left ELSE bottom, brLayer, CD.InterestSize[extended2], IF channelData.extendTopOrRight THEN 0 ELSE rightOrTopExtend]; IF (IF inX THEN CD.InterestSize[obj1].y ELSE CD.InterestSize[obj1].x)#(IF inX THEN CD.InterestSize[obj2].y ELSE CD.InterestSize[obj2].x) THEN ERROR; bottomOrLeftObj _ MakeFakeObject[data.internal, channelData.bottomOrLeftWires, channelData.inX, trLayer, IF inX THEN bottom ELSE left]; topOrRightObj _ MakeFakeObject[data.internal, channelData.topOrRightWires, channelData.inX, trLayer, IF inX THEN top ELSE right]; params _ NEW [PWRoute.RouterParamsRec _ [ trunkLayer: channelData.trunkLayer, branchLayer: channelData.branchLayer, wireWidthProc: channelData.wireWidthProc, technologyKey: technologyKey, signalSinglePinNets: FALSE, -- SIGNAL if there are any single pin nets opt: noIncompletes -- return the first correct routing ]]; CedarProcess.CheckAbort[]; CedarProcess.SetPriority[background]; channel _ PWRoute.MakeChannel[ obj1: obj1, obj2: obj2, bottomOrLeftObj: bottomOrLeftObj, topOrRightObj: topOrRightObj, params: params, isX: channelData.inX ! Route.Signal => {PW.WriteF["*** Routing warning: %g\n", IO.rope[explanation]]}]; CedarProcess.SetPriority[priority]; IF channel=NIL OR NARROW [channel.specificRef, CD.CellPtr].contents=NIL THEN ERROR; obj _ (IF inX THEN PW.AbutX ELSE PW.AbutY)[extended1, channel, extended2]; }; DecorateChannel: PWCore.DecorateProc = { channelData: ChannelData _ NARROW [CoreProperties.GetCellTypeProp[cellType, $ChannelData]]; PWCore.DecorateFlatten[cellType, obj, IF channelData.inX THEN PWCore.SortInX ELSE PWCore.SortInY]; SanityCheck[cellType, channelData.bottomOrLeftWires, IF channelData.inX THEN bottom ELSE left]; SanityCheck[cellType, channelData.topOrRightWires, IF channelData.inX THEN top ELSE right]; }; SchChannel: PWCore.AttributesProc = { DecideIfInX: PROC [i1, i2: CD.Instance] RETURNS [inX: BOOL] ~ { dx: INT _ ABS[i1.location.x-i2.location.x]; dy: INT _ ABS[i1.location.y-i2.location.y]; RETURN[dx>dy]; }; CheckEachPin: CoreGeometry.EachWirePinProc = { SELECT side FROM bottom => IF inX THEN bottomOrLeftWires _ CONS[wire, bottomOrLeftWires]; top => IF inX THEN topOrRightWires _ CONS[wire, topOrRightWires]; right => IF ~inX THEN topOrRightWires _ CONS[wire, topOrRightWires]; left => IF ~inX THEN bottomOrLeftWires _ CONS[wire, bottomOrLeftWires]; ENDCASE => ERROR; }; channelData: ChannelData; inX, verticalM2, flushTopOrRight: BOOL; prop: REF; bottomOrLeftWires, topOrRightWires: Wires _ NIL; decoration: CoreGeometry.Decoration _ Sisyph.mode.decoration; data: CoreClasses.RecordCellType _ NARROW[cellType.data]; i1, i2: CD.Instance; prop _ CoreProperties.GetCellTypeProp[cellType, $Metal2IsVertical]; verticalM2 _ IF prop#NIL THEN NARROW[prop, REF BOOL]^ ELSE TRUE; prop _ CoreProperties.GetCellTypeProp[cellType, $FlushTopOrRight]; flushTopOrRight _ IF prop#NIL THEN NARROW[prop, REF BOOL]^ ELSE TRUE; IF data.size#2 THEN ERROR; -- exactly two cells per channel i1 _ CoreGeometry.GetTransf[decoration, data.instances[0]]; i2 _ CoreGeometry.GetTransf[decoration, data.instances[1]]; inX _ DecideIfInX[i1, i2]; PWCore.SortInstances[Sisyph.mode.decoration, cellType, IF inX THEN PWCore.SortInX ELSE PWCore.SortInY]; [] _ CoreGeometry.EnumerateWireSides[decoration, cellType, CheckEachPin]; channelData _ NEW[ChannelDataRec _ [ inX: inX, extend: TRUE, extendTopOrRight: flushTopOrRight, bottomOrLeftWires: bottomOrLeftWires, topOrRightWires: topOrRightWires, trunkLayer: IF verticalM2 AND inX THEN "metal2" ELSE "metal", branchLayer: IF verticalM2 AND inX THEN "metal" ELSE "metal2", wireWidthProc: GndAndVdd25Met2MinWidth]]; CoreProperties.PutCellTypeProp[cellType, $ChannelData, channelData]; }; SanityCheck: PROC [cellType: CellType, wires: Wires, side: CoreGeometry.Side] = { WHILE wires#NIL DO EachSortedPin: CoreGeometry.EachSortedPinProc = {quit _ wire=wires.first}; IF wires.first.size=0 AND NOT CoreGeometry.EnumerateSortedSides[PWCore.extractMode.decoration, cellType, side, EachSortedPin] THEN SIGNAL SanityFailed[]; wires _ wires.rest; ENDLOOP; }; SanityFailed: SIGNAL [] = CODE; -- call implementor MakeOutline: PROC [cellInstance: CoreClasses.CellInstance, internal: Wire, iSide: CoreGeometry.Side, iLayer: CD.Layer, iSize: CD.Position, displacement: INT] RETURNS [obj: CD.Object] ~ { AddPinToOutline: CoreGeometry.EachWirePinProc ~ { inst: CD.Instance; name: ROPE; pos: CD.Position; IF wire.size#0 THEN ERROR; name _ CoreOps.GetFullWireNames[internal, CoreClasses.CorrespondingActual[cellInstance, wire]].first; IF side#iSide OR layer#iLayer THEN RETURN; pos _ SELECT side FROM left => [0, min+displacement], right => [iSize.x-minW, min+displacement], top => [min+displacement, iSize.y-minW], bottom => [min+displacement, 0], ENDCASE => ERROR; inst _ PW.IncludeInCell[obj, CDSymbolicObjects.CreatePin[IF side=left OR side=right THEN [minW, max-min] ELSE [max-min, minW]], pos]; CDSymbolicObjects.SetLayer[inst, layer]; CDSymbolicObjects.SetName[inst, name]; }; minW: INT _ CDSimpleRules.MinWidth[iLayer]-1; obj _ PW.CreateEmptyCell[]; [] _ PWCore.InterestRect[cellInstance.type]; -- to make sure the cellType is decorated [] _ CoreGeometry.EnumerateNonOverlappingSides[PWCore.extractMode.decoration, cellInstance.type, AddPinToOutline]; PW.SetInterestRect[obj, iSize]; PW.RepositionCell[obj]; obj _ obj; -- for debugging }; MakeFakeObject: PROC [internal: Wire, sideWires: LIST OF Wire, inX: BOOL, layer: CD.Layer, purposeSide: CoreGeometry.Side] RETURNS [obj: PW.Object] ~ { AppendPin: PROC [wire: Wire] ~ { inst: CD.Instance; name: ROPE _ CoreOps.GetFullWireNames[internal, wire].first; inst _ PW.IncludeInCell[obj, CDSymbolicObjects.CreatePin[[minW, minW]], pos]; CDSymbolicObjects.SetLayer[inst, layer]; CDSymbolicObjects.SetName[inst, name]; pos _ IF inX THEN [pos.x+delta, pos.y] ELSE [pos.x, pos.y+delta]; }; minW: INT _ CDSimpleRules.MinWidth[layer]; delta: INT _ CDSimpleRules.MinDist[layer, layer]+minW; pos: CD.Position _ [0, 0]; obj _ PW.CreateEmptyCell[]; [] _ PW.IncludeInCell[obj, CDSimpleRules.Rect[[1, 1], CD.undefLayer], [1, 1]]; -- to avoid reposionning empty cell FOR list: LIST OF Wire _ sideWires, list.rest WHILE list#NIL DO IF list.first.size=0 THEN AppendPin[list.first] ELSE [] _ CoreOps.VisitRootAtomics[list.first, AppendPin]; ENDLOOP; [] _ CDCells.SetInterestRect[obj, IF inX THEN [-minW, IF purposeSide=top THEN 0 ELSE -5*minW, pos.x, IF purposeSide=top THEN 10*minW ELSE minW] ELSE [IF purposeSide=left THEN -5*minW ELSE 0, -minW, IF purposeSide=left THEN minW ELSE 10*minW, pos.y]]; PW.RepositionCell[obj]; }; Filler: PROC [sourceCT: CellType, inX: BOOL, extLayer: CD.Layer, extension: INT, extendTopOrRight: BOOL] RETURNS [extended: CD.Object] = { source: CD.Object _ PWCore.Layout[sourceCT]; AddPinToExtension: CoreGeometry.EachWirePinProc = { IF wire.size#0 THEN ERROR; IF side#(IF inX THEN (IF extendTopOrRight THEN top ELSE bottom) ELSE (IF extendTopOrRight THEN right ELSE left)) OR layer#extLayer THEN RETURN; [] _ PW.IncludeInCell[ obj, CDSimpleRules.Rect[IF inX THEN [max-min, extension] ELSE [extension, max-min], layer], IF inX THEN [min, 0] ELSE [0, min] ]; }; obj: CD.Object; size: CD.Position _ CD.InterestSize[source]; IF extension=0 THEN RETURN [source]; obj _ PW.CreateEmptyCell[]; [] _ PWCore.InterestRect[sourceCT]; -- to make sure the cellType is decorated [] _ CoreGeometry.EnumerateNonOverlappingSides[PWCore.extractMode.decoration, sourceCT, AddPinToExtension]; PW.SetInterestRect[obj, IF inX THEN [size.x, extension] ELSE [extension, size.y]]; PW.RepositionCell[obj]; extended _ (IF inX THEN PW.AbutY ELSE PW.AbutX)[IF extendTopOrRight THEN source ELSE obj, IF extendTopOrRight THEN obj ELSE source]; }; [] _ PWCore.RegisterLayoutAtom[$Channel, Channel, DecorateChannel]; [] _ PWCore.RegisterLayoutAtom[$CR, Channel, DecorateChannel, SchChannel]; END. PWCoreRouteImpl.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reversed. Bertrand Serlet November 6, 1986 1:31:31 am PST Louis Monier June 14, 1986 5:16:38 pm PDT Last Edited by: Louis Monier November 7, 1986 6:32:09 pm PST Last Edited by: Ross November 7, 1986 3:41:23 pm PST -- check if interestRects do not match -- Make fake objects signalCoincidentPins: FALSE, -- SIGNAL if there any pins are coincident We make a sanity check that all wires appearing in bottomOrLeftWires and topOrRightWires have pins on their relative sides. -- the cellType is a record with exactly two instances [cellType: Core.CellType] -- inX if dx>dy; I know that tis implementation is bogus; used CDBasics [wire: Core.Wire, instance: CD.Instance, min: INT, max: INT, side: CoreGeometry.Side, layer: CD.Layer] RETURNS [quit: BOOL _ FALSE] -- remember to include only atomic wires!!! -- Given the layout associated with the cellType, this proc extracts all the pins located on the edge of the channel which have the appropriate layer and are part (full name) of the public of the channel; it assemble these pins into a fake object passed to the router. -- A cell containing only pins (plus a rectangle; hack!) whose posiiton and size does not matter; used to specify the sides of the channel to the router. Κ š˜– "Cedar" stylešœ™Jšœ Οmœ7™BIcode™/K™)K™Jšœ)˜)—KšœD˜DKšœ˜—K˜šŸ œžœ@˜Qšžœžœžœ˜KšŸ œ=˜JKš žœžœžœažœžœ˜™K˜Kšžœ˜—K˜K˜—šŸ œžœžœ‘˜3K˜—K™ŒšŸ œžœ\žœžœžœžœžœ ˜Ίš œ"˜1Kšœžœ ˜Kšœžœ˜ Kšœžœ ˜Kšžœ žœžœ˜Kšœe˜eKšžœ žœžœžœ˜*šœžœž˜Kšœ˜Kšœ*˜*Kšœ(˜(Kšœ ˜ Kšžœžœ˜—Kš œžœ0žœ žœ žœžœ˜…Kšœ(˜(Kšœ&˜&K˜—Kšœžœ$˜-Kšœžœ˜Jšœ-‘)˜VKšœr˜rKšžœ˜Kšžœ˜Kšœ ‘˜K˜—K˜K™™šŸœžœžœžœ žœ žœ(žœžœ ˜—š  œžœ˜ Kšœžœ ˜Kšœžœ2˜