<> <> <> <> <> DIRECTORY CD, CDBasics, CDCells, CDOrient, CDSymbolicObjects, CDProperties, CDRects, CDSimpleRules, CMosB, IO, Onion, OnionArc, PW, PWPins, SymTab, TerminalIO; OnionImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, CDCells, CDOrient, CDSymbolicObjects, CDProperties, CDRects, CDSimpleRules, CMosB, OnionArc, IO, PW, PWPins, SymTab, TerminalIO EXPORTS Onion = BEGIN OPEN Onion; defaultLayersParameters: PUBLIC LayersParameters = NEW [LayersParametersRec _ [ radialLayer: CMosB.met, ringLayer: CMosB.met2, ringWidth: RingWidthIs4 wireExtendProc: WireExtendMetToMet ]]; channelDefaultParameters: PUBLIC LayersParameters = NEW [LayersParametersRec _ [ radialLayer: CMosB.met, ringLayer: CMosB.met2, ringWidth: RingWidthIs4 wireExtendProc: WireExtendMetToMet ]]; WireExtendMetToMet: PUBLIC WireExtendProc = { wire _ CDRects.CreateRect[[length, width], CMosB.met]; }; WireExtendPolToMetForPads: PUBLIC WireExtendProc = { nb: INT _ MAX[8, width]; -- for computing how many! wire _ CDCells.CreateEmptyCell[]; [] _ PW.IncludeInCell[wire, CDRects.CreateRect[[length-14, width], CMosB.met], [0, 0]]; FOR i: INT IN [0 .. nb/8) DO [] _ PW.IncludeInCell[wire, CDSimpleRules.Contact[CMosB.pol, CMosB.met], [length-14, 8*i]] ENDLOOP; [] _ PW.IncludeInCell[wire, CDRects.CreateRect[[6, width], CMosB.pol], [length-6, 0]]; CDCells.SetInterestRect[wire, [0, 0, length, width]]; [] _ CDCells.RepositionCell[wire, NIL]; }; RingWidthIs4 Arc: TYPE = OnionArc.Arc; <<>> RotateSide: PROC [side: PWPins.Side] RETURNS [PWPins.Side] = { RETURN [SELECT side FROM bottom => right, right => top, top => left, left => bottom, ENDCASE => ERROR]; }; <> 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.Instance _ 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]; }; IncludePin: PUBLIC PROC [cell: CD.Object, name: ROPE, layer: CD.Layer, size, position: CD.Position, orientation: CD.Orientation _ 0] RETURNS [newInst: CD.Instance] = { newInst _ PW.IncludeInCell[cell: cell, obj: CDSymbolicObjects.CreatePin[size], position: position, orientation: orientation].newInst; CDSymbolicObjects.SetName[newInst, name]; CDSymbolicObjects.SetLayer[newInst, layer]; }; IncludeContact: PUBLIC PROC [cell: CD.Object, side: PWPins.Side, layer1, layer2: CD.Layer, size: INT, position: CD.Position, orientation: CD.Orientation _ 0] = { contact: CD.Object _ CDSimpleRules.Contact[layer1, layer2]; contactSize: INT _ contact.size.x; -- **** WRONG nb: INT _ MAX[contactSize, size]; -- **** WRONG FOR i: INT IN [0..nb/contactSize) DO [] _ PW.IncludeInCell[ cell, contact, SELECT side FROM left => [position.x, position.y+i*contactSize], right => [position.x-contactSize, position.y+i*contactSize], bottom => [position.x+i*contactSize, position.y], top => [position.x+i*contactSize, position.y-contactSize], ENDCASE => ERROR]; ENDLOOP; }; <> Center: PUBLIC PROC [inner, outer: CD.Object] 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 [obj: CD.Object] RETURNS [inner: CD.Object] = { dist: INT _ 18; ---???? ExtendPinOnEdge: PWPins.InstanceEnumerator -- [inst: CD.Instance] RETURNS [quit: BOOL _ FALSE] -- = { newInst: CD.Instance; location: CD.Position _ CDBasics.SubPoints[ inst.location, CDBasics.BaseOfRect[CD.InterestRect[obj]]]; realSize: CD.Position _ CDOrient.OrientedSize[inst.ob.size, inst.orientation]; side: PWPins.Side _ PWPins.GetSide[obj, inst].side; newInst _ IncludePin[ inner, CDSymbolicObjects.GetName[inst], CMosB.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]; <> [] _ PW.IncludeInCell[ inner, CDRects.CreateRect[ SELECT side FROM left, right => [dist, realSize.y], top, bottom => [realSize.x, dist], ENDCASE => ERROR, CDSymbolicObjects.GetLayer[inst]], 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 CDSymbolicObjects.GetLayer[inst] FROM CMosB.met => {}; CMosB.met2 => { IncludeContact[inner, side, CMosB.met, CMosB.met2, (SELECT side FROM left, right => realSize.y, bottom, top => realSize.x, ENDCASE => ERROR), SELECT side FROM left => [location.x-dist, location.y], right => [location.x+realSize.x+dist, location.y], bottom => [location.x, location.y-dist], top => [location.x, location.y+realSize.y+dist], ENDCASE => ERROR]; }; CMosB.pol => { IncludeContact[inner, side, CMosB.met, CMosB.pol, (SELECT side FROM left, right => realSize.y, bottom, top => realSize.x, ENDCASE => ERROR), SELECT side FROM left => [location.x-dist, location.y], right => [location.x+realSize.x+dist, location.y], bottom => [location.x, location.y-dist], top => [location.x, location.y+realSize.y+dist], ENDCASE => ERROR]; }; ENDCASE => TerminalIO.WriteF["**** MakeInner: Layer unknown for extending pin %g. Extension WRONG!!!\n", IO.rope[CDSymbolicObjects.GetName[inst]]]; }; inst: CD.Instance; inner _ CDCells.CreateEmptyCell[]; inst _ PW.IncludeInCell[inner, obj]; CDProperties.PutInstanceProp[inst, $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]; }; <<-- innerPos is the location of the origin of inner in the coord system of outer>> LRSRouteOnce: PUBLIC PROC [inner, outer: CD.Object, innerPos: CD.Position, params: LayersParameters _ defaultLayersParameters] RETURNS [cell: CD.Object, newInnerPos: CD.Position, status: Status] = { contactWidth: INT; innerRect: CD.Rect = CDBasics.MoveRect[CDBasics.RectAt[[0, 0], CDBasics.SizeOfRect[CD.InterestRect[inner]]], innerPos]; -- in the outer coord system <<>> <> InnerPinLocation: PROC [pin: CD.Instance] RETURNS [location: CD.Position] = { location _ CDBasics.AddPoints[CDBasics.SubPoints[pin.location, CDBasics.BaseOfRect[CD.InterestRect[inner]]], innerPos]; }; <> OuterPinLocation: PROC [pin: CD.Instance] RETURNS [location: CD.Position] = { location _ CDBasics.SubPoints[pin.location, CDBasics.BaseOfRect[CD.InterestRect[outer]]]; }; <<>> <> InnerPinBiProjection: PROC [pin: CD.Instance] 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.Instance] 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.InstanceEnumerator -- [inst: CD.Instance] RETURNS [quit: BOOL _ FALSE] -- = { name: ROPE _ CDSymbolicObjects.GetName[inst]; net: Net _ FetchNet[nets, name]; IF CDSymbolicObjects.GetLayer[inst]#params.radialLayer THEN TerminalIO.WriteF["*** Pin %g discarded: not of radialLayer material.\n", IO.rope[name]] ELSE net.innerPins _ CONS[inst, net.innerPins]; StoreNet[nets, name, net]; }; AddOuterPinToNets: PWPins.InstanceEnumerator -- [inst: CD.Instance] RETURNS [quit: BOOL _ FALSE] -- = { name: ROPE _ CDSymbolicObjects.GetName[inst]; net: Net _ FetchNet[nets, name]; net.outerPins _ CONS[inst, 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]]+CDSimpleRules.MinDist[params.ringLayer, params.ringLayer]; net.arc _ OnionArc.EmptyArc[CDBasics.Extend[innerRect, pitch]]; FOR innerPins: LIST OF CD.Instance _ 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.Instance _ 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.Instance _ net.outerPins, outerPins.rest WHILE outerPins#NIL DO matches: BOOL _ FALSE; FOR innerPins: LIST OF CD.Instance _ 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.Instance _ 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.Instance _ 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.Instance] 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.Instance] 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] + CDSimpleRules.MinDist[params.ringLayer, params.ringLayer]; outerMax _ MAX [outerMax, outerMin + contactWidth] + CDSimpleRules.MinDist[params.ringLayer, params.ringLayer]; 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.NotOverlinsting[assignedArc, net.arc, CDSimpleRules.MinDist[params.ringLayer, params.ringLayer]+contactWidth] OR params.ringWidth[key]#netRingWidth) THEN RETURN; minEval _ net.eval; minNetName _ key; }; <<>> <<-- Generation of the geometry>> <<>> <> IncludeInCellSide: PROC [ob: CD.Object, 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; [] _ PW.IncludeInCell[cell: cell, obj: 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]; }; IncludeContactSide: PROC [side: PWPins.Side, size: INT, position: CD.Position] = { nb: INT _ MAX[contactWidth, size]; FOR i: INT IN [0..nb/contactWidth) DO IncludeInCellSide[CDSimpleRules.Contact[params.radialLayer, params.ringLayer], side, SELECT side FROM left => [position.x, position.y-contactWidth*i], right => [position.x, position.y+contactWidth*i], bottom => [position.x+contactWidth*i, position.y], top => [position.x-contactWidth*i, position.y], ENDCASE => ERROR]; ENDLOOP }; DrawRingBit: OnionArc.EachSegBitProc -- [min: D2Basic.Number, max: D2Basic.Number, side: Onion.PWPins.Side] -- = { SELECT side FROM bottom => [] _ PW.IncludeInCell[cell, CDRects.CreateRect[[max-min, netRingWidth], params.ringLayer], [min-assignedArc.rect.x1, 0]]; right => [] _ PW.IncludeInCell[cell, CDRects.CreateRect[[netRingWidth, max-min], params.ringLayer], [assignedArc.rect.x2-assignedArc.rect.x1-netRingWidth, min-assignedArc.rect.y1]]; top => [] _ PW.IncludeInCell[cell, CDRects.CreateRect[[max-min, netRingWidth], params.ringLayer], [min-assignedArc.rect.x1, assignedArc.rect.y2-assignedArc.rect.y1-netRingWidth]]; left => [] _ PW.IncludeInCell[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 [inst: CD.Instance, name: ROPE] = { <> side: PWPins.Side _ PWPins.GetSide[outer, inst].side; size: CD.Position _ CDOrient.OrientedSize[inst.ob.size, inst.orientation]; position: CD.Position _ OuterPinLocation[inst]; 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; IncludeContactSide[side, (SELECT side FROM left, right => size.y, bottom, top => size.x, ENDCASE => ERROR), pos]; IncludePinSide[name, side, size, pos]; }; net: Net _ NARROW [val]; quit _ FALSE; IF ~net.chosen THEN {IF net.eval#LAST[INT] THEN TerminalIO.WriteF["%g ", IO.rope[key]]; RETURN}; FOR outerPins: LIST OF CD.Instance _ 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 [inst: CD.Instance, chosen: BOOL, name: ROPE] = { side: PWPins.Side _ PWPins.GetSide[inner, inst].side; size: CD.Position _ CDOrient.OrientedSize[inst.ob.size, inst.orientation]; rectSize: CD.Position _ size; pos: CD.Position; -- base of wire in the outer coord system position: CD.Position _ InnerPinLocation[inst]; 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) IncludeContactSide[side, (SELECT side FROM left, right => size.y, bottom, top => size.x, ENDCASE => ERROR), pos] ELSE -- add a pin -- IncludePinSide[name, side, size, pos]; }; net: Net _ NARROW [val]; quit _ FALSE; FOR innerPins: LIST OF CD.Instance _ 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.Instance _ net.outerPins, outerPins.rest WHILE outerPins#NIL DO FOR innerPins: LIST OF CD.Instance _ 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.Object _ params.wireExtendProc[width, length]; [] _ PW.IncludeInCell[ cell: cell, obj: 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 <> IF CDSimpleRules.Contact[params.radialLayer, params.ringLayer]=NIL THEN { TerminalIO.WriteF["ImpossibleTechnology: I do not know how to contact radialLayer and ringLayer!\n"]; ERROR; }; contactWidth _ CDBasics.SizeOfRect[CD.InterestRect[CDSimpleRules.Contact[params.radialLayer, params.ringLayer]]].x; -- ****** ??W?!?!?!?? WRONG! <<-- Emergency break>> IF ~CDBasics.Inside[innerRect, CDBasics.RectAt[[0, 0], CDBasics.SizeOfRect[CD.InterestRect[outer]]]] THEN {TerminalIO.WriteF["**** 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 TerminalIO.WriteF["*** Net: %g has only 1 pin. Not routed\n", IO.rope[deletedNets.first]]; [] _ 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]; <> TerminalIO.WriteF["Allocating a new track\n"]; DO Count: PROC [pins: LIST OF CD.Instance] RETURNS [rope: ROPE] = { count: INT _ 0; WHILE pins#NIL DO count _ count+1; pins _ pins.rest ENDLOOP; rope _ IO.PutR[IO.int[count]]; }; minNet: Net; minEval _ LAST[INT]; minNetName _ NIL; [] _ SymTab.Pairs[nets, ChooseMinEval]; IF minEval=LAST[INT] THEN EXIT; IF minEval>=LAST[INT]/2 THEN TerminalIO.WriteF["****** 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; TerminalIO.WriteF["Routing the net : %g innerPins: %g outerPins: %g Cost: %g\n", IO.rope[minNetName], IO.rope[Count[minNet.innerPins]], IO.rope[Count[minNet.outerPins]], IO.int[minNet.eval]]; ENDLOOP; <<>> <<-- We now generate geometry>> cell _ CDCells.CreateEmptyCell[]; IF assignedArc=NIL THEN { <> IF params.wireExtendProc#NIL THEN [] _ SymTab.Pairs[nets, ExtendAllWires]; <> [] _ PW.IncludeInCell[cell, inner, innerPos]; IF params.wireExtendProc#NIL THEN [] _ PW.IncludeInCell[cell, outer, [0, 0]]; [] _ CDCells.RepositionCell[cell, NIL]; RETURN[cell, [0, 0], finishedAll]; } ELSE { <<-- We shrink the assignedArc.rect if some sides are unused>> IF OnionArc.NotOverlinsting[assignedArc, NEW[OnionArc.ArcRec _ [rect: assignedArc.rect, segs: LIST [NEW[OnionArc.SegRec _ [assignedArc.rect.y2, assignedArc.rect.y1, left, left]]]]], CDSimpleRules.MinDist[params.ringLayer, params.ringLayer]+contactWidth] THEN assignedArc.rect.x1 _ innerRect.x1; IF OnionArc.NotOverlinsting[assignedArc, NEW[OnionArc.ArcRec _ [rect: assignedArc.rect, segs: LIST [NEW[OnionArc.SegRec _ [assignedArc.rect.y1, assignedArc.rect.y2, right, right]]]]], CDSimpleRules.MinDist[params.ringLayer, params.ringLayer]+contactWidth] THEN assignedArc.rect.x2 _ innerRect.x2; IF OnionArc.NotOverlinsting[assignedArc, NEW[OnionArc.ArcRec _ [rect: assignedArc.rect, segs: LIST [NEW[OnionArc.SegRec _ [assignedArc.rect.x1, assignedArc.rect.x2, bottom, bottom]]]]], CDSimpleRules.MinDist[params.ringLayer, params.ringLayer]+contactWidth] THEN assignedArc.rect.y1 _ innerRect.y1; IF OnionArc.NotOverlinsting[assignedArc, NEW[OnionArc.ArcRec _ [rect: assignedArc.rect, segs: LIST [NEW[OnionArc.SegRec _ [assignedArc.rect.x2, assignedArc.rect.x1, top, top]]]]], CDSimpleRules.MinDist[params.ringLayer, params.ringLayer]+contactWidth] THEN assignedArc.rect.y2 _ innerRect.y2; <<-- We position the inner cell>> CDProperties.PutInstanceProp[ PW.IncludeInCell[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>> TerminalIO.WriteF["Non routed nets: "]; [] _ SymTab.Pairs[nets, DepositOuterContacts]; TerminalIO.WriteF["\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]; RETURN[cell, CDBasics.BaseOfRect[assignedArc.rect], doneOnce]; }; }; LRSRoute: PUBLIC PROC [inner, outer: CD.Object, innerPos: CD.Position, params: LayersParameters _ defaultLayersParameters] RETURNS [cell: CD.Object, status: Status] = { status _ doneOnce; WHILE status=doneOnce DO [inner, innerPos, status] _ LRSRouteOnce[inner, outer, innerPos, params]; ENDLOOP; cell _ inner; }; END.