<> <> <> <> <> DIRECTORY CD, CDBasics, CDCells, CDDirectory, CDOrient, CDPinObjects, CDProperties, CDRects, CDX, CMos, CMosContacts, Convert, Onion, OnionArc, PWPins, Rope, SymTab, TerminalIO; OnionImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, CDCells, CDDirectory, CDOrient, CDPinObjects, CDProperties, CDRects, CDX, CMos, CMosContacts, OnionArc, Convert, PWPins, Rope, SymTab, TerminalIO EXPORTS Onion = BEGIN OPEN Onion; left: PWPins.Side = PWPins.left; right: PWPins.Side = PWPins.right; top: PWPins.Side = PWPins.top; bottom: PWPins.Side = PWPins.bottom; Output: PROC [r1, r2, r3, r4, r5, r6, r7, r8: ROPE _ NIL] = { TerminalIO.WriteRope[Rope.Cat[Rope.Cat[r1, r2, r3, r4], Rope.Cat[r5, r6, r7, r8]]]; }; defaultLayersParameters: PUBLIC LayersParameters = NEW [LayersParametersRec _ [ radialLayer: CMos.met, ringLayer: CMos.met2, ringWidth: RingWidthIs8, contact: CMosContacts.CreateMmCon[10], ringRingDist: 8, wireExtendProc: WireExtendMetToMet ]]; channelDefaultParameters: PUBLIC LayersParameters = NEW [LayersParametersRec _ [ radialLayer: CMos.met, ringLayer: CMos.met2, ringWidth: RingWidthIs8, contact: CMosContacts.CreateMmCon[10], ringRingDist: 8, wireExtendProc: WireExtendMetToMet ]]; WireExtendMetToMet: PUBLIC WireExtendProc = { wire _ CDRects.CreateRect[[length, width], CMos.met]; }; WireExtendPolToMetForPads: PUBLIC WireExtendProc = { nb: INT _ MAX[8, width]; -- for computing how many! wire _ CDCells.CreateEmptyCell[]; [] _ IncludeOb[wire, CDRects.CreateRect[[length-14, width], CMos.met], [0, 0]]; FOR i: INT IN [0 .. nb/8) DO [] _ IncludeOb[wire, CMosContacts.CreatePolyCon[8], [length-14, 8*i]] ENDLOOP; [] _ IncludeOb[wire, CDRects.CreateRect[[6, width], CMos.pol], [length-6, 0]]; CDCells.SetInterestRect[wire, [0, 0, length, width]]; [] _ CDCells.RepositionCell[wire, NIL]; [] _ CDDirectory.Include[design, wire, "WireExtendPolToMetForPads"]; }; RingWidthIs8: PUBLIC RingWidthProc = {ringWidth _ 8}; Arc: TYPE = OnionArc.Arc; <> Net: TYPE = REF NetRec; NetRec: TYPE = RECORD [ chosen: BOOL _ FALSE, -- chosen for being routed eval: INT _ 0, -- evaluation function arc: Arc _ NIL, -- arc used by this net innerPins, outerPins: LIST OF CD.ApplicationPtr _ NIL -- pins of the net ]; FetchNet: PROC [nets: SymTab.Ref, name: ROPE] RETURNS [net: Net] = { found: BOOL; val: SymTab.Val; [found, val] _ SymTab.Fetch[nets,name]; net _ IF found THEN NARROW[val] ELSE NEW[NetRec]; }; StoreNet: PROC [nets: SymTab.Ref, name: ROPE, net: Net] = { [] _ SymTab.Store[nets, name, net]; }; <> IncludeOb: PUBLIC PROC [cell, ob: CD.ObPtr, position: CD.Position _ [0, 0], orientation: CD.Orientation _ 0] RETURNS [newApp: CD.ApplicationPtr] = { newApp _ CDX.IncludeOb[cell: cell, ob: ob, position: position, cellCSystem: interrestCoords, obCSystem: interrestCoords, mode: dontPropagate, orientation: orientation].newApp; }; IncludePin: PUBLIC PROC [cell: CD.ObPtr, name: ROPE, layer: CD.Layer, size, position: CD.Position, orientation: CD.Orientation _ 0] RETURNS [newApp: CD.ApplicationPtr] = { newApp _ IncludeOb[cell: cell, ob: CDPinObjects.CreatePinOb[size], position: position, orientation: orientation].newApp; CDPinObjects.SetName[newApp, name]; CDPinObjects.SetLayer[newApp, layer]; }; <> Center: PUBLIC PROC [inner, outer: CD.ObPtr] RETURNS [innerPos: CD.Position] = { innerPos _ CDBasics.SubPoints[ CDBasics.SizeOfRect[CD.InterestRect[outer]], CDBasics.SizeOfRect[CD.InterestRect[inner]]]; innerPos.x _ innerPos.x/2; innerPos.y _ innerPos.y/2; }; <> MakeInner: PUBLIC PROC [design: CD.Design, obj: CD.ObPtr] RETURNS [inner: CD.ObPtr] = { dist: INT _ 18; ---???? ExtendPinOnEdge: PWPins.AppEnumerator -- [app: CD.ApplicationPtr] RETURNS [quit: BOOL _ FALSE] -- = { newApp: CD.ApplicationPtr; location: CD.Position _ CDBasics.SubPoints[ app.location, CDBasics.BaseOfRect[CD.InterestRect[obj]]]; realSize: CD.Position _ CDOrient.OrientedSize[app.ob.size, app.orientation]; side: PWPins.Side _ PWPins.GetSide[obj, app].side; newApp _ IncludePin[ inner, CDPinObjects.GetName[app], CMos.met, realSize, SELECT side FROM right => [location.x+dist, location.y], left => [location.x-dist, location.y], top => [location.x, location.y+dist], bottom => [location.x, location.y-dist], ENDCASE => ERROR]; <> [] _ IncludeOb[ inner, CDRects.CreateRect[ SELECT side FROM left, right => [dist, realSize.y], top, bottom => [realSize.x, dist], ENDCASE => ERROR, CDPinObjects.GetLayer[app]], SELECT side FROM left => [location.x-dist, location.y], right => [location.x+realSize.x, location.y], bottom => [location.x, location.y-dist], top => [location.x, location.y+realSize.y], ENDCASE => ERROR]; <> SELECT CDPinObjects.GetLayer[app] FROM CMos.met => {}; CMos.met2 => { nb: INT _ MAX[10, (SELECT side FROM left, right => realSize.y, bottom, top => realSize.x, ENDCASE => ERROR)]; FOR i: INT IN [0..nb/10) DO [] _ IncludeOb[ inner, CMosContacts.CreateMmCon[10], SELECT side FROM left => [location.x-dist, location.y+i*10], right => [location.x-10+realSize.x+dist, location.y+i*10], bottom => [location.x+i*10, location.y-dist], top => [location.x+i*10, location.y-10+realSize.y+dist], ENDCASE => ERROR]; ENDLOOP; }; CMos.pol => { nb: INT _ MAX[8, (SELECT side FROM left, right => realSize.y, bottom, top => realSize.x, ENDCASE => ERROR)]; FOR i: INT IN [0..nb/8) DO [] _ IncludeOb[ inner, CMosContacts.CreatePolyCon[8], SELECT side FROM left => [location.x-dist, location.y+i*8], right => [location.x-8+realSize.x+dist, location.y+i*8], bottom => [location.x+i*8, location.y-dist], top => [location.x+i*8, location.y-8+realSize.y+dist], ENDCASE => ERROR]; ENDLOOP; }; ENDCASE => Output["**** MakeInner: Layer unknowm for extending pin ", CDPinObjects.GetName[app], ". Extension WRONG!!!\n"]; }; app: CD.ApplicationPtr; inner _ CDCells.CreateEmptyCell[]; app _ IncludeOb[inner, obj]; CDProperties.PutPropOnApplication[app, $StopEnumerateDeepPins, $StopEnumerateDeepPins]; [] _ PWPins.EnumerateEdgePins[obj, ExtendPinOnEdge]; CDCells.SetInterestRect[inner, CDBasics.Extend[ CDBasics.RectAt[[0, 0], CDBasics.SizeOfRect[CD.InterestRect[obj]]], dist]]; [] _ CDCells.RepositionCell[inner, NIL]; [] _ CDDirectory.Include[design, inner, Rope.Cat[CDDirectory.Name[obj], "@MadeInner"]]; }; <<-- innerPos is the location of the origin of inner in the coord system of outer>> LRSRouteOnce: PUBLIC PROC [design: CD.Design, inner, outer: CD.ObPtr, innerPos: CD.Position, params: LayersParameters _ defaultLayersParameters] RETURNS [cell: CD.ObPtr, newInnerPos: CD.Position, status: Status] = { contactWidth: INT _ params.contact.size.x; innerRect: CD.Rect = CDBasics.MoveRect[CDBasics.RectAt[[0, 0], CDBasics.SizeOfRect[CD.InterestRect[inner]]], innerPos]; -- in the outer coord system <<>> <> InnerPinLocation: PROC [pin: CD.ApplicationPtr] RETURNS [location: CD.Position] = { location _ CDBasics.AddPoints[CDBasics.SubPoints[pin.location, CDBasics.BaseOfRect[CD.InterestRect[inner]]], innerPos]; }; <> OuterPinLocation: PROC [pin: CD.ApplicationPtr] RETURNS [location: CD.Position] = { location _ CDBasics.SubPoints[pin.location, CDBasics.BaseOfRect[CD.InterestRect[outer]]]; }; <<>> <> InnerPinBiProjection: PROC [pin: CD.ApplicationPtr] RETURNS [min, max: INT] = { rect: CD.Rect _ CDOrient.RectAt[InnerPinLocation[pin], pin.ob.size, pin.orientation]; SELECT PWPins.GetSide[inner, pin].side FROM bottom, top => {min _ rect.x1; max _ rect.x2}; left, right => {min _ rect.y1; max _ rect.y2}; ENDCASE => ERROR; }; <> OuterPinBiProjection: PROC [pin: CD.ApplicationPtr] RETURNS [min, max: INT] = { rect: CD.Rect _ CDOrient.RectAt[OuterPinLocation[pin], pin.ob.size, pin.orientation]; SELECT PWPins.GetSide[outer, pin].side FROM bottom, top => {min _ rect.x1; max _ rect.x2}; left, right => {min _ rect.y1; max _ rect.y2}; ENDCASE => ERROR; }; OuterCoordsToCellCoords: PROC [outerPos: CD.Position] RETURNS [cellPos: CD.Position] = { cellPos _ CDBasics.SubPoints[outerPos, CDBasics.BaseOfRect[assignedArc.rect]]; }; <<-- Procs for parsing the pins into nets>> AddInnerPinToNets: PWPins.AppEnumerator -- [app: CD.ApplicationPtr] RETURNS [quit: BOOL _ FALSE] -- = { name: ROPE _ CDPinObjects.GetName[app]; net: Net _ FetchNet[nets, name]; IF CDPinObjects.GetLayer[app]#params.radialLayer THEN Output["*** Pin ", name, " discarded: not of radialLayer material.\n"] ELSE net.innerPins _ CONS[app, net.innerPins]; StoreNet[nets, name, net]; }; AddOuterPinToNets: PWPins.AppEnumerator -- [app: CD.ApplicationPtr] RETURNS [quit: BOOL _ FALSE] -- = { name: ROPE _ CDPinObjects.GetName[app]; net: Net _ FetchNet[nets, name]; net.outerPins _ CONS[app, net.outerPins]; StoreNet[nets, name, net]; }; <<>> <<-- Choice of possible nets>> <<>> <> ComputeArc: SymTab.EachPairAction -- [key: SymTab.Key, val: SymTab.Val] RETURNS [quit: BOOL] -- = { net: Net _ NARROW [val]; pitch: INT = MAX[contactWidth, params.ringWidth[key]]+params.ringRingDist; net.arc _ OnionArc.EmptyArc[CDBasics.Extend[innerRect, pitch]]; FOR innerPins: LIST OF CD.ApplicationPtr _ net.innerPins, innerPins.rest WHILE innerPins#NIL DO side: PWPins.Side _ PWPins.GetSide[inner, innerPins.first].side; min, max: INT; [min, max] _ InnerPinBiProjection[innerPins.first]; SELECT side FROM bottom, right => max _ MAX[max, min+contactWidth]; top, left => min _ MIN[min, max-contactWidth]; ENDCASE => ERROR; net.arc _ OnionArc.ConnectSegBitToArc[min, max, side, net.arc]; ENDLOOP; FOR outerPins: LIST OF CD.ApplicationPtr _ net.outerPins, outerPins.rest WHILE outerPins#NIL DO side: PWPins.Side _ PWPins.GetSide[outer, outerPins.first].side; min, max: INT; [min, max] _ OuterPinBiProjection[outerPins.first]; SELECT side FROM bottom, right => max _ MAX[max, min+contactWidth]; top, left => min _ MIN[min, max-contactWidth]; ENDCASE => ERROR; net.arc _ OnionArc.ConnectSegBitToArc[min, max, side, net.arc]; ENDLOOP; quit _ FALSE; }; <<>> <<-- Computation of the evaluation function of a Net, i.e. LAST[INT]/2+Length if there is an innerPin roughly (less than design rules) in front of some outerPin of the net, LAST[INT] if all pins of the net are matching some pins of the same net, Length else. Length is OnionArc.Length[arc]+ Perimeter[Arc.rect].>> ComputeEval: SymTab.EachPairAction -- [key: SymTab.Key, val: SymTab.Val] RETURNS [quit: BOOL] -- = { net: Net _ NARROW [val]; allOuterPinsMatchSomeInnerPin: BOOL _ TRUE; quit _ FALSE; FOR outerPins: LIST OF CD.ApplicationPtr _ net.outerPins, outerPins.rest WHILE outerPins#NIL DO matches: BOOL _ FALSE; FOR innerPins: LIST OF CD.ApplicationPtr _ net.innerPins, innerPins.rest WHILE innerPins#NIL DO IF Faces[innerPins.first, outerPins.first] THEN {matches _ TRUE; EXIT}; ENDLOOP; IF ~matches THEN {allOuterPinsMatchSomeInnerPin _ FALSE; EXIT}; ENDLOOP; IF allOuterPinsMatchSomeInnerPin THEN {net.eval _ LAST[INT]; RETURN}; net.eval _ OnionArc.Length[net.arc] + net.arc.rect.x2 - net.arc.rect.x1 + net.arc.rect.y2 - net.arc.rect.y1; FOR outerPins: LIST OF CD.ApplicationPtr _ net.outerPins, outerPins.rest WHILE outerPins#NIL DO FindDifferentNetFacing: SymTab.EachPairAction -- [key: SymTab.Key, val: SymTab.Val] RETURNS [quit: BOOL] -- = { thisNet: Net _ NARROW[val]; quit _ FALSE; IF thisNet=net THEN RETURN; FOR innerPins: LIST OF CD.ApplicationPtr _ thisNet.innerPins, innerPins.rest WHILE innerPins#NIL DO IF RoughlyFaces[innerPins.first, outerPins.first] THEN {quit _ TRUE; RETURN}; ENDLOOP; }; <> IF SymTab.Pairs[nets, FindDifferentNetFacing] THEN {net.eval _ net.eval + LAST [INT] /2; RETURN}; ENDLOOP; }; <<>> <<-- Given two pins, checks if they faces each other>> Faces: PROC [innerPin, outerPin: CD.ApplicationPtr] RETURNS [faces: BOOL] = { side: PWPins.Side _ PWPins.GetSide[inner, innerPin].side; faces _ side=PWPins.GetSide[outer, outerPin].side AND OuterPinBiProjection[outerPin]=InnerPinBiProjection[innerPin]; }; <<-- Given two pins, checks if they faces each other, taking into account design rules>> RoughlyFaces: PROC [innerPin, outerPin: CD.ApplicationPtr] RETURNS [faces: BOOL] = { side: PWPins.Side _ PWPins.GetSide[inner, innerPin].side; innerMin, innerMax, outerMin, outerMax: INT; [innerMin, innerMax] _ InnerPinBiProjection[innerPin]; [outerMin, outerMax] _ OuterPinBiProjection[outerPin]; innerMax _ MAX [innerMax, innerMin + contactWidth] + params.ringRingDist; outerMax _ MAX [outerMax, outerMin + contactWidth] + params.ringRingDist; faces _ side=PWPins.GetSide[outer, outerPin].side AND (innerMin IN [outerMin .. outerMax] OR outerMin IN [innerMin .. innerMax]); }; ChooseMinEval: SymTab.EachPairAction -- [key: SymTab.Key, val: SymTab.Val] RETURNS [quit: BOOL] -- = { net: Net _ NARROW [val]; quit _ FALSE; IF net.chosen OR net.eval>minEval OR net.eval=LAST[INT] THEN RETURN; IF assignedArc#NIL AND (net.eval>=LAST[INT]/2 OR ~CDBasics.Inside[net.arc.rect, assignedArc.rect] OR ~OnionArc.NotOverlapping[assignedArc, net.arc, params.ringRingDist+contactWidth] OR params.ringWidth[key]#netRingWidth) THEN RETURN; minEval _ net.eval; minNetName _ key; }; <<>> <<-- Generation of the geometry>> <<>> <> IncludeInCellSide: PROC [ob: CD.ObPtr, side: PWPins.Side, position: CD.Position, orientation: CD.Orientation _ 0] = { position _ OuterCoordsToCellCoords[position]; SELECT side FROM left => position.y _ position.y-ob.size.y; right => position.x _ position.x-ob.size.x; bottom => {}; top => {position.x _ position.x-ob.size.x; position.y _ position.y-ob.size.y}; ENDCASE => ERROR; [] _ IncludeOb[cell: cell, ob: ob, position: position, orientation: orientation]; }; IncludePinSide: PROC [name: ROPE, side: PWPins.Side, size, position: CD.Position] = { pinDeep: INT _ 2; position _ OuterCoordsToCellCoords[position]; SELECT side FROM left => position.y _ position.y-size.y; right => position.x _ position.x-size.x; bottom => {}; top => {position.x _ position.x-size.x; position.y _ position.y-size.y}; ENDCASE => ERROR; [] _ IncludePin[cell, name, params.radialLayer, size, position]; }; DrawRingBit: OnionArc.EachSegBitProc -- [min: D2Basic.Number, max: D2Basic.Number, side: Onion.PWPins.Side] -- = { SELECT side FROM bottom => [] _ IncludeOb[cell, CDRects.CreateRect[[max-min, netRingWidth], params.ringLayer], [min-assignedArc.rect.x1, 0]]; right => [] _ IncludeOb[cell, CDRects.CreateRect[[netRingWidth, max-min], params.ringLayer], [assignedArc.rect.x2-assignedArc.rect.x1-netRingWidth, min-assignedArc.rect.y1]]; top => [] _ IncludeOb[cell, CDRects.CreateRect[[max-min, netRingWidth], params.ringLayer], [min-assignedArc.rect.x1, assignedArc.rect.y2-assignedArc.rect.y1-netRingWidth]]; left => [] _ IncludeOb[cell, CDRects.CreateRect[[netRingWidth, max-min], params.ringLayer], [0, min-assignedArc.rect.y1]]; ENDCASE => ERROR; }; DepositOuterContacts: SymTab.EachPairAction -- [key: SymTab.Key, val: SymTab.Val] RETURNS [quit: BOOL] -- = { DrawOuterPin: PROC [app: CD.ApplicationPtr, name: ROPE] = { <> side: PWPins.Side _ PWPins.GetSide[outer, app].side; size: CD.Position _ CDOrient.OrientedSize[app.ob.size, app.orientation]; position: CD.Position _ OuterPinLocation[app]; pos: CD.Position _ SELECT side FROM left => [assignedArc.rect.x1, position.y + size.y], right => [assignedArc.rect.x2, position.y], bottom => [position.x, assignedArc.rect.y1], top => [position.x + size.x, assignedArc.rect.y2], ENDCASE => ERROR; nb: INT _ MAX[contactWidth, (SELECT side FROM left, right => size.y, bottom, top => size.x, ENDCASE => ERROR)]; IncludePinSide[name, side, size, pos]; FOR i: INT IN [0..nb/contactWidth) DO IncludeInCellSide[params.contact, side, SELECT side FROM left => [pos.x, pos.y-contactWidth*i], right => [pos.x, pos.y+contactWidth*i], bottom => [pos.x+contactWidth*i, pos.y], top => [pos.x-contactWidth*i, pos.y], ENDCASE => ERROR]; ENDLOOP; }; net: Net _ NARROW [val]; quit _ FALSE; IF ~net.chosen THEN {IF net.eval#LAST[INT] THEN Output[key, " "]; RETURN}; FOR outerPins: LIST OF CD.ApplicationPtr _ net.outerPins, outerPins.rest WHILE outerPins#NIL DO DrawOuterPin[outerPins.first, key]; ENDLOOP; }; <> DepositInnerWiresEtAl: SymTab.EachPairAction -- [key: SymTab.Key, val: SymTab.Val] RETURNS [quit: BOOL] -- = { DrawInnerPin: PROC [app: CD.ApplicationPtr, chosen: BOOL, name: ROPE] = { side: PWPins.Side _ PWPins.GetSide[inner, app].side; size: CD.Position _ CDOrient.OrientedSize[app.ob.size, app.orientation]; rectSize: CD.Position _ size; pos: CD.Position; -- base of wire in the outer coord system position: CD.Position _ InnerPinLocation[app]; nb: INT _ MAX[contactWidth, (SELECT side FROM left, right => size.y, bottom, top => size.x, ENDCASE => ERROR)]; SELECT side FROM left => { pos _ [assignedArc.rect.x1, position.y + size.y]; -- origin of wire and Al in the outer coord system rectSize.x _ innerRect.x1-assignedArc.rect.x1; }; right => { pos _ [assignedArc.rect.x2, position.y]; -- origin of wire and Al in the outer coord system rectSize.x _ assignedArc.rect.x2-innerRect.x2; }; bottom => { pos _ [position.x, assignedArc.rect.y1]; -- origin of wire and Al in the outer coord system rectSize.y _ innerRect.y1-assignedArc.rect.y1; }; top => { pos _ [position.x + size.x, assignedArc.rect.y2]; -- origin of wire and Al in the outer coord system rectSize.y _ assignedArc.rect.y2-innerRect.y2; }; ENDCASE => ERROR; IF rectSize.x#0 AND rectSize.y#0 THEN IncludeInCellSide[CDRects.CreateRect[rectSize, params.radialLayer], side, pos]; IF chosen THEN -- add contact(s) FOR i: INT IN [0..nb/contactWidth) DO IncludeInCellSide[params.contact, side, SELECT side FROM left => [pos.x, pos.y-contactWidth*i], right => [pos.x, pos.y+contactWidth*i], bottom => [pos.x+contactWidth*i, pos.y], top => [pos.x-contactWidth*i, pos.y], ENDCASE => ERROR]; ENDLOOP ELSE -- add a pin -- IncludePinSide[name, side, size, pos]; }; net: Net _ NARROW [val]; quit _ FALSE; FOR innerPins: LIST OF CD.ApplicationPtr _ net.innerPins, innerPins.rest WHILE innerPins#NIL DO DrawInnerPin[innerPins.first, net.chosen, key]; ENDLOOP; }; ExtendAllWires: SymTab.EachPairAction -- [key: SymTab.Key, val: SymTab.Val] RETURNS [quit: BOOL] -- = { net: Net _ NARROW [val]; quit _ FALSE; IF net.outerPins#NIL AND net.outerPins.rest=NIL AND net.innerPins=NIL THEN RETURN; -- only 1 outerPin and 0 innerPin FOR outerPins: LIST OF CD.ApplicationPtr _ net.outerPins, outerPins.rest WHILE outerPins#NIL DO FOR innerPins: LIST OF CD.ApplicationPtr _ net.innerPins, innerPins.rest WHILE innerPins#NIL DO IF Faces[innerPins.first, outerPins.first] THEN { innerPos: CD.Position _ InnerPinLocation[innerPins.first]; outerPos: CD.Position _ OuterPinLocation[outerPins.first]; innerSize: CD.Position _ CDOrient.OrientedSize[innerPins.first.ob.size, innerPins.first.orientation]; outerSize: CD.Position _ CDOrient.OrientedSize[outerPins.first.ob.size, outerPins.first.orientation]; side: PWPins.Side _ PWPins.GetSide[inner, innerPins.first].side; length: INT _ SELECT side FROM left => innerPos.x - outerPos.x - outerSize.x, right => outerPos.x - innerPos.x - innerSize.x, bottom => innerPos.y - outerPos.y - outerSize.y, top => outerPos.y - innerPos.y - innerSize.y, ENDCASE => ERROR; width: INT _ SELECT side FROM left, right => MIN[innerSize.y, outerSize.y], bottom, top => MIN[innerSize.x, outerSize.x], ENDCASE => ERROR; wire: CD.ObPtr _ params.wireExtendProc[design, width, length]; [] _ IncludeOb[ cell: cell, ob: wire, position: SELECT side FROM left => [outerPos.x + outerSize.x, outerPos.y], right => [outerPos.x - length, outerPos.y], bottom => [outerPos.x, outerPos.y + outerSize.y], top => [outerPos.x, outerPos.y - length], ENDCASE => ERROR, orientation: SELECT side FROM left => CDOrient.rotate180, right => CDOrient.original, bottom => CDOrient.rotate270, top => CDOrient.rotate90, ENDCASE => ERROR ]; EXIT; }; ENDLOOP; ENDLOOP; }; assignedArc: Arc _ NIL; nets: SymTab.Ref _ SymTab.Create[]; minEval: INT; minNetName: ROPE; -- for choosing the nets netRingWidth: INT _ 0; -- all nets on the same track have the same width <<-- Emergency break>> IF ~CDBasics.Inside[innerRect, CDBasics.RectAt[[0, 0], CDBasics.SizeOfRect[CD.InterestRect[outer]]]] THEN {Output["**** Routing Impossible (Too big) ****\n**** Current state returned! ****\n"]; RETURN[inner, innerPos, impossible];}; <<>> <<-- Parsing all the pins to sort them by nets>> [] _ PWPins.EnumerateEdgePins[inner, AddInnerPinToNets]; [] _ PWPins.EnumerateEdgePins[outer, AddOuterPinToNets]; <<>> <<-- We delete all nets containing only 1 pin>> BEGIN deletedNets: LIST OF ROPE _ NIL; ToBeDeleted: SymTab.EachPairAction -- [key: SymTab.Key, val: SymTab.Val] RETURNS [quit: BOOL] -- = { net: Net _ NARROW [val]; quit _ FALSE; IF (net.innerPins#NIL AND net.innerPins.rest=NIL AND net.outerPins=NIL) OR (net.outerPins#NIL AND net.outerPins.rest=NIL AND net.innerPins=NIL) THEN deletedNets _ CONS[key, deletedNets]; }; [] _ SymTab.Pairs[nets, ToBeDeleted]; WHILE deletedNets#NIL DO Output["*** Net: ", deletedNets.first, " has only 1 pin. Not routed\n"]; [] _ SymTab.Delete[nets, deletedNets.first]; deletedNets _ deletedNets.rest; ENDLOOP; END; <<>> <<-- We compute the Arc necessited by the net for being routed>> [] _ SymTab.Pairs[nets, ComputeArc]; <> [] _ SymTab.Pairs[nets, ComputeEval]; <> Output["Allocating a new track\n"]; DO Count: PROC [pins: LIST OF CD.ApplicationPtr] RETURNS [rope: ROPE] = { count: INT _ 0; WHILE pins#NIL DO count _ count+1; pins _ pins.rest ENDLOOP; rope _ Convert.RopeFromInt[count]; }; minNet: Net; minEval _ LAST[INT]; minNetName _ NIL; [] _ SymTab.Pairs[nets, ChooseMinEval]; IF minEval=LAST[INT] THEN EXIT; IF minEval>=LAST[INT]/2 THEN Output["****** ROUTING IS WRONG: at least 2 different nets are facing each other. No cure possible until Dogleg is introduced in Onion!\n"]; minNet _ FetchNet[nets, minNetName]; IF assignedArc=NIL THEN netRingWidth _ params.ringWidth[minNetName]; assignedArc _ IF assignedArc=NIL THEN minNet.arc ELSE OnionArc.Union[assignedArc, minNet.arc]; minNet.chosen _ TRUE; Output["Routing the net : ", minNetName, " innerPins: ", Count[minNet.innerPins], Rope.Cat[" outerPins: ", Count[minNet.outerPins], " Cost: ", Convert.RopeFromInt[minNet.eval], "\n"]]; ENDLOOP; <<>> <<-- We now generate geometry>> cell _ CDCells.CreateEmptyCell[]; IF assignedArc=NIL THEN { <> IF params.wireExtendProc#NIL THEN [] _ SymTab.Pairs[nets, ExtendAllWires]; <> [] _ IncludeOb[cell, inner, innerPos]; IF params.wireExtendProc#NIL THEN [] _ IncludeOb[cell, outer, [0, 0]]; [] _ CDCells.RepositionCell[cell, NIL]; [] _ CDDirectory.Include[design, cell, Rope.Cat["RoutingRing-", minNetName]]; RETURN[cell, [0, 0], finishedAll]; } ELSE { <<-- We shrink the assignedArc.rect if some sides are unused>> IF OnionArc.NotOverlapping[assignedArc, NEW[OnionArc.ArcRec _ [rect: assignedArc.rect, segs: LIST [NEW[OnionArc.SegRec _ [assignedArc.rect.y2, assignedArc.rect.y1, left, left]]]]], params.ringRingDist+contactWidth] THEN assignedArc.rect.x1 _ innerRect.x1; IF OnionArc.NotOverlapping[assignedArc, NEW[OnionArc.ArcRec _ [rect: assignedArc.rect, segs: LIST [NEW[OnionArc.SegRec _ [assignedArc.rect.y1, assignedArc.rect.y2, right, right]]]]], params.ringRingDist+contactWidth] THEN assignedArc.rect.x2 _ innerRect.x2; IF OnionArc.NotOverlapping[assignedArc, NEW[OnionArc.ArcRec _ [rect: assignedArc.rect, segs: LIST [NEW[OnionArc.SegRec _ [assignedArc.rect.x1, assignedArc.rect.x2, bottom, bottom]]]]], params.ringRingDist+contactWidth] THEN assignedArc.rect.y1 _ innerRect.y1; IF OnionArc.NotOverlapping[assignedArc, NEW[OnionArc.ArcRec _ [rect: assignedArc.rect, segs: LIST [NEW[OnionArc.SegRec _ [assignedArc.rect.x2, assignedArc.rect.x1, top, top]]]]], params.ringRingDist+contactWidth] THEN assignedArc.rect.y2 _ innerRect.y2; <<-- We position the inner cell>> CDProperties.PutPropOnApplication[ IncludeOb[cell, inner, CDBasics.SubPoints[ CDBasics.BaseOfRect[innerRect], CDBasics.BaseOfRect[assignedArc.rect]]], $StopEnumerateDeepPins, $StopEnumerateDeepPins]; <<-- We place the sides of the routing (in metal2)>> OnionArc.EnumerateSegBits[assignedArc, DrawRingBit]; <<-- We deposit contacts facing the outer pins which touch the routing ring. By the way we print the names of non-chosen nets>> Output["Non routed nets: "]; [] _ SymTab.Pairs[nets, DepositOuterContacts]; Output["\n"]; <<-- We deposit wires in metal for inner pins and if the pin belongs to the net, then add a contact, else add a pin.>> [] _ SymTab.Pairs[nets, DepositInnerWiresEtAl]; <<-- We reposition and include in the design>> CDCells.SetInterestRect[cell, [0, 0, assignedArc.rect.x2-assignedArc.rect.x1, assignedArc.rect.y2-assignedArc.rect.y1]]; [] _ CDCells.RepositionCell[cell, NIL]; [] _ CDDirectory.Include[design, cell, Rope.Cat["RoutingRing-", minNetName]]; RETURN[cell, CDBasics.BaseOfRect[assignedArc.rect], doneOnce]; }; }; LRSRoute: PUBLIC PROC [design: CD.Design, inner, outer: CD.ObPtr, innerPos: CD.Position, params: LayersParameters _ defaultLayersParameters] RETURNS [cell: CD.ObPtr, status: Status] = { status _ doneOnce; WHILE status=doneOnce DO [inner, innerPos, status] _ LRSRouteOnce[design, inner, outer, innerPos, params]; ENDLOOP; cell _ inner; }; SwitchBox: PUBLIC PROC [design: CD.Design, bottomOb, rightOb, topOb, leftOb: CD.ObPtr, params: LayersParameters _ channelDefaultParameters] RETURNS [cell: CD.ObPtr, status: Status] = { inner: CD.ObPtr _ CDCells.CreateEmptyCell[]; outer: CD.ObPtr _ CDCells.CreateEmptyCell[]; currentSide: PWPins.Side; currentOb: CD.ObPtr; size: CD.Position _ [ MAX[ CDBasics.SizeOfRect[CD.InterestRect[bottomOb]].x, CDBasics.SizeOfRect[CD.InterestRect[topOb]].x], MAX[ CDBasics.SizeOfRect[CD.InterestRect[rightOb]].y, CDBasics.SizeOfRect[CD.InterestRect[leftOb]].y]]; AddPin: PWPins.AppEnumerator -- [app: CD.ApplicationPtr] RETURNS [quit: BOOL _ FALSE] -- = { name: ROPE _ CDPinObjects.GetName[app]; realSize: CD.Position _ CDOrient.OrientedSize[app.ob.size, app.orientation]; location: CD.Position _ CDBasics.SubPoints[app.location, CDBasics.BaseOfRect[CD.InterestRect[currentOb]]]; IF PWPins.GetSide[currentOb, app].side#((currentSide+2 ) MOD 4) THEN RETURN; IF CDPinObjects.GetLayer[app]#params.radialLayer THEN { Output["*** Pin ", name, " discarded: not of radialLayer material.\n"] ; RETURN; }; [] _ IncludePin[outer, name, CDPinObjects.GetLayer[app], realSize, SELECT currentSide FROM PWPins.bottom => [location.x, 0], PWPins.top => [location.x, size.y-realSize.y], PWPins.left => [0, location.y], PWPins.right => [size.x-realSize.x, location.y], ENDCASE => ERROR]; }; [] _ IncludeOb[inner, CDRects.CreateRect[[8, 8], params.ringLayer]]; [] _ CDCells.RepositionCell[inner, NIL]; [] _ CDDirectory.Include[design, inner, "EmptyCellForHeartOfSwitchBox"]; currentSide _ PWPins.bottom; currentOb _ bottomOb; [] _ PWPins.EnumerateEdgePins[currentOb, AddPin]; currentSide _ PWPins.top; currentOb _ topOb; [] _ PWPins.EnumerateEdgePins[currentOb, AddPin]; currentSide _ PWPins.left; currentOb _ leftOb; [] _ PWPins.EnumerateEdgePins[currentOb, AddPin]; currentSide _ PWPins.right; currentOb _ rightOb; [] _ PWPins.EnumerateEdgePins[currentOb, AddPin]; CDCells.SetInterestRect[outer, [0, 0, size.x, size.y]]; [] _ CDCells.RepositionCell[outer, NIL]; [] _ CDDirectory.Include[design, outer, "EmptyCellForSkinOfSwitchBox"]; [cell, status] _ LRSRoute[design, inner, outer, Center[inner, outer], params]; }; Channel: PUBLIC PROC [design: CD.Design, left, right: CD. ObPtr, size: INT, params: LayersParameters _ channelDefaultParameters] RETURNS [cell: CD.ObPtr, status: Status] = { top: CD.ObPtr _ CDCells.CreateEmptyCell[]; [] _ IncludeOb[top, CDRects.CreateRect[[size, 8], params.ringLayer]]; [] _ CDCells.RepositionCell[top, NIL]; [] _ CDDirectory.Include[design, top, "EmptyTopForChannel"]; [cell, status] _ SwitchBox[design, top, right, top, left, params]; }; END.