<> <> <> <> <> DIRECTORY CD, CDBasics, CDCells, CDDirectory, CDOrient, CDPinObjects, CDProperties, CDRects, CDSimpleRules, CMos, Core, CoreOps, IO, Onion, OnionArc, PW, PWCore, PWPins, RefTab, Rope, TerminalIO; OnionImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, CDCells, CDDirectory, CDOrient, CDPinObjects, CDProperties, CDRects, CDSimpleRules, CMos, CoreOps, IO, OnionArc, PW, PWCore, PWPins, RefTab, Rope, TerminalIO EXPORTS Onion = BEGIN OPEN Onion; defaultLayersParameters: PUBLIC LayersParameters = NEW [LayersParametersRec _ [ radialLayer: CMos.met, ringLayer: CMos.met2, ringWidth: RingWidthIs8, wireExtendProc: WireExtendMetToMet ]]; channelDefaultParameters: PUBLIC LayersParameters = NEW [LayersParametersRec _ [ radialLayer: CMos.met, ringLayer: CMos.met2, ringWidth: RingWidthIs8, 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[]; [] _ PW.IncludeInCell[wire, CDRects.CreateRect[[length-14, width], CMos.met], [0, 0]]; FOR i: INT IN [0 .. nb/8) DO [] _ PW.IncludeInCell[wire, CDSimpleRules.Contact[CMos.pol, CMos.met], [length-14, 8*i]] ENDLOOP; [] _ PW.IncludeInCell[wire, CDRects.CreateRect[[6, width], CMos.pol], [length-6, 0]]; CDCells.SetInterestRect[wire, [0, 0, length, width]]; [] _ CDCells.RepositionCell[wire, NIL]; IF design#NIL THEN [] _ CDDirectory.Include[design, wire, "WireExtendPolToMetForPads"]; }; RingWidthIs8: PUBLIC RingWidthProc = {ringWidth _ 8}; Arc: TYPE = OnionArc.Arc; <<>> RotateSide: PROC [side: Side] RETURNS [Side] = { RETURN [SELECT side FROM bottom => right, right => top, top => left, left => bottom, ENDCASE => ERROR]; }; <> Net: TYPE = REF NetRec; NetRec: TYPE = RECORD [ name: ROPE _ NIL, -- name of the net. Unicity not guaranteed 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: RefTab.Ref, wire: Wire] RETURNS [net: Net] = { found: BOOL; val: RefTab.Val; [found, val] _ RefTab.Fetch[nets, wire]; net _ IF found THEN NARROW [val] ELSE NEW [NetRec]; }; IncludePin: PUBLIC PROC [cell: CD.Object, wire: Wire, layer: CD.Layer, size, position: CD.Position, orientation: CD.Orientation _ 0] RETURNS [newInst: CD.Instance] = { nets: RefTab.Ref _ NARROW [CDProperties.GetPropFromObject[cell, PWCore.netsProp]]; pins: LIST OF CD.Instance; newInst _ PW.IncludeInCell[cell: cell, obj: CDPinObjects.CreatePinOb[size], position: position, orientation: orientation].newInst; pins _ CONS [newInst, NARROW [RefTab.Fetch[nets, wire].val]]; [] _ RefTab.Store[nets, wire, pins]; CDPinObjects.SetLayer[newInst, layer]; CDPinObjects.SetName[newInst, CoreOps.GetShortWireName[wire]]; }; IncludeContact: PUBLIC PROC [cell: CD.Object, side: 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 [design: CD.Design, obj: CD.Object] RETURNS [inner: CD.Object] = { dist: INT _ 18; ---???? ExtendPinOnEdge: PWCore.EachNetProc = { FOR insts: LIST OF CD.Instance _ pins, insts.rest WHILE insts#NIL DO inst: CD.Instance _ insts.first; 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: Side _ PWPins.GetSide[obj, inst].side; newInst _ IncludePin[ inner, wire, 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]; <> [] _ PW.IncludeInCell[ inner, CDRects.CreateRect[ SELECT side FROM left, right => [dist, realSize.y], top, bottom => [realSize.x, dist], ENDCASE => ERROR, CDPinObjects.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 CDPinObjects.GetLayer[inst] FROM CMos.met => {}; CMos.met2, CMos.pol => { IncludeContact[inner, side, CMos.met, CDPinObjects.GetLayer[inst], (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.WriteRopes["**** MakeInner: Layer unknown for extending pin ", CoreOps.GetShortWireName[wire], ". Extension WRONG!!!\n"]; ENDLOOP; }; inst: CD.Instance; inner _ CDCells.CreateEmptyCell[]; CDProperties.PutPropOnObject[inner, PWCore.netsProp, RefTab.Create[]]; inst _ PW.IncludeInCell[inner, obj]; CDProperties.PutPropOnInstance[inst, $StopEnumerateDeepPins, $StopEnumerateDeepPins]; [] _ PWCore.EnumerateNets[PWCore.FindNets[obj], ExtendPinOnEdge]; CDCells.SetInterestRect[inner, CDBasics.Extend[ CDBasics.RectAt[[0, 0], CDBasics.SizeOfRect[CD.InterestRect[obj]]], dist]]; [] _ CDCells.RepositionCell[inner, NIL]; IF design#NIL THEN [] _ 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.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: PWCore.EachNetProc = { net: Net _ FetchNet[nets, wire]; IF net.name=NIL THEN net.name _ CoreOps.GetShortWireName[wire]; FOR insts: LIST OF CD.Instance _ pins, insts.rest WHILE insts#NIL DO inst: CD.Instance _ insts.first; name: ROPE _ CDPinObjects.GetName[inst]; IF PWPins.GetSide[inner, inst]=none THEN ERROR; IF CDPinObjects.GetLayer[inst]#params.radialLayer THEN TerminalIO.WriteF["*** Inner Pin %g on net %g discarded: not of radialLayer material.\n", IO.rope[name], IO.rope[CoreOps.GetShortWireName[wire]]] ELSE net.innerPins _ CONS [inst, net.innerPins]; ENDLOOP; [] _ RefTab.Store[nets, wire, net]; }; AddOuterPinToNets: PWCore.EachNetProc = { net: Net _ FetchNet[nets, wire]; IF net.name=NIL THEN net.name _ CoreOps.GetShortWireName[wire]; FOR insts: LIST OF CD.Instance _ pins, insts.rest WHILE insts#NIL DO inst: CD.Instance _ insts.first; name: ROPE _ CDPinObjects.GetName[inst]; IF PWPins.GetSide[outer, inst]=none THEN ERROR; IF CDPinObjects.GetLayer[inst]#params.radialLayer THEN TerminalIO.WriteF["*** Outer Pin %g on net %g discarded: not of radialLayer material.\n", IO.rope[name], IO.rope[CoreOps.GetShortWireName[wire]]] ELSE net.outerPins _ CONS [inst, net.outerPins]; ENDLOOP; [] _ RefTab.Store[nets, wire, net]; }; <<>> <<-- Choice of possible nets>> <<>> <> ComputeArc: RefTab.EachPairAction -- [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOL] -- = { net: Net _ NARROW [val]; wire: Wire _ NARROW [key]; pitch: INT = MAX [contactWidth, params.ringWidth[wire]]+CDSimpleRules.MinDist[params.ringLayer, params.ringLayer]; quit _ FALSE; net.arc _ OnionArc.EmptyArc[CDBasics.Extend[innerRect, pitch]]; FOR innerPins: LIST OF CD.Instance _ net.innerPins, innerPins.rest WHILE innerPins#NIL DO side: 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: 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: RefTab.EachPairAction -- [key: RefTab.Key, val: RefTab.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: RefTab.EachPairAction -- [key: RefTab.Key, val: RefTab.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 RefTab.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: 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: 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: RefTab.EachPairAction -- [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOL] -- = { net: Net _ NARROW [val]; wire: Wire _ NARROW [key]; 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[wire]#netRingWidth) THEN RETURN; minEval _ net.eval; minNet _ net; minKey _ wire; }; <<>> <<-- Generation of the geometry>> <<>> <> IncludeInCellSide: PROC [ob: CD.Object, side: 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 [wire: Wire, side: 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, wire, params.radialLayer, size, position]; }; IncludeContactSide: PROC [side: 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.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: RefTab.EachPairAction -- [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOL] -- = { DrawOuterPin: PROC [inst: CD.Instance, wire: Wire] = { <> side: 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[wire, side, size, pos]; }; net: Net _ NARROW [val]; wire: Wire _ NARROW [key]; quit _ FALSE; IF ~net.chosen THEN {IF net.eval#LAST[INT] THEN TerminalIO.WriteRopes[net.name, " "]; RETURN}; FOR outerPins: LIST OF CD.Instance _ net.outerPins, outerPins.rest WHILE outerPins#NIL DO DrawOuterPin[outerPins.first, wire]; ENDLOOP; }; <> DepositInnerWiresEtAl: RefTab.EachPairAction -- [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOL] -- = { DrawInnerPin: PROC [inst: CD.Instance, chosen: BOOL, wire: Wire] = { side: 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[wire, side, size, pos]; }; net: Net _ NARROW [val]; wire: Wire _ NARROW [key]; quit _ FALSE; FOR innerPins: LIST OF CD.Instance _ net.innerPins, innerPins.rest WHILE innerPins#NIL DO DrawInnerPin[innerPins.first, net.chosen, wire]; ENDLOOP; }; ExtendAllWires: RefTab.EachPairAction -- [key: RefTab.Key, val: RefTab.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: 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[design, 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: RefTab.Ref _ RefTab.Create[]; minEval: INT; minNet: Net; minKey: Wire; -- for choosing the nets netRingWidth: INT _ 0; -- all nets on the same track have the same width cell _ CDCells.CreateEmptyCell[]; CDProperties.PutPropOnObject[cell, PWCore.netsProp, RefTab.Create[]]; <> IF CDSimpleRules.Contact[params.radialLayer, params.ringLayer]=NIL THEN { TerminalIO.WriteRope["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.WriteRope["**** Routing Impossible (Too big) ****\n**** Current state returned! ****\n"]; RETURN[inner, innerPos, impossible];}; <<>> <<-- Parsing all the pins to sort them by nets>> [] _ PWCore.EnumerateNets[PWCore.FindNets[inner], AddInnerPinToNets]; [] _ PWCore.EnumerateNets[PWCore.FindNets[outer], AddOuterPinToNets]; <<>> <<-- We delete all nets containing only 1 pin>> BEGIN deletedNets: LIST OF Wire _ NIL; ToBeDeleted: RefTab.EachPairAction -- [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOL] -- = { wire: Wire _ NARROW [key]; 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 [wire, deletedNets]; }; [] _ RefTab.Pairs[nets, ToBeDeleted]; WHILE deletedNets#NIL DO TerminalIO.WriteRopes["*** Net: ", CoreOps.GetShortWireName[deletedNets.first], " has only 1 pin. Not routed\n"]; [] _ RefTab.Delete[nets, deletedNets.first]; deletedNets _ deletedNets.rest; ENDLOOP; END; <<>> <<-- We compute the Arc necessited by the net for being routed>> [] _ RefTab.Pairs[nets, ComputeArc]; <> [] _ RefTab.Pairs[nets, ComputeEval]; <> TerminalIO.WriteRope["Allocating a new track\n"]; DO Count: PROC [pins: LIST OF CD.Instance] RETURNS [count: INT _ 0] = { WHILE pins#NIL DO count _ count+1; pins _ pins.rest ENDLOOP; }; minEval _ LAST [INT]; minNet _ NIL; [] _ RefTab.Pairs[nets, ChooseMinEval]; IF minEval=LAST [INT] THEN EXIT; IF minEval>=LAST [INT]/2 THEN TerminalIO.WriteRope["****** ROUTING IS WRONG: at least 2 different nets are facing each other. No cure possible until Dogleg is introduced in Onion!\n"]; IF assignedArc=NIL THEN netRingWidth _ params.ringWidth[minKey]; 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[minNet.name], IO.int[Count[minNet.innerPins]], IO.int[Count[minNet.outerPins]], IO.int[minNet.eval]]; ENDLOOP; <<>> <<-- We now generate geometry>> IF assignedArc=NIL THEN { <> IF params.wireExtendProc#NIL THEN [] _ RefTab.Pairs[nets, ExtendAllWires]; <> [] _ PW.IncludeInCell[cell, inner, innerPos]; IF params.wireExtendProc#NIL THEN [] _ PW.IncludeInCell[cell, outer, [0, 0]]; [] _ CDCells.RepositionCell[cell, NIL]; IF design#NIL THEN [] _ CDDirectory.Include[design, cell, "LastRoutingRing"]; 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.PutPropOnInstance[ 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.WriteRope["Non routed nets: "]; [] _ RefTab.Pairs[nets, DepositOuterContacts]; TerminalIO.WriteRope["\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.>> [] _ RefTab.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]; IF design#NIL THEN [] _ CDDirectory.Include[design, cell, "RoutingRing-"]; RETURN[cell, CDBasics.BaseOfRect[assignedArc.rect], doneOnce]; }; }; LRSRoute: PUBLIC PROC [design: CD.Design, 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[design, inner, outer, innerPos, params]; ENDLOOP; cell _ inner; }; <> <> <> <> <> <> <> <> <> <> <> <<>> <> <> <> <> <> <> <> <> <<};>> <<[] _ IncludePin[outer, name, CDPinObjects.GetLayer[inst], realSize, SELECT currentSide FROM>> < [location.x, 0],>> < [location.x, size.y-realSize.y],>> < [0, location.y],>> < [size.x-realSize.x, location.y],>> < ERROR];>> <<};>> <<[] _ PW.IncludeInCell[inner, CDRects.CreateRect[[8, 8], params.ringLayer]];>> <<[] _ CDCells.RepositionCell[inner, NIL];>> <> <<>> <> <<[] _ PWPins.EnumerateEdgePins[currentOb, AddPin];>> <> <<[] _ PWPins.EnumerateEdgePins[currentOb, AddPin];>> <> <<[] _ PWPins.EnumerateEdgePins[currentOb, AddPin];>> <> <<[] _ PWPins.EnumerateEdgePins[currentOb, AddPin];>> <<>> <> <<[] _ CDCells.RepositionCell[outer, NIL];>> <> <<>> <<[cell, status] _ LRSRoute[design, inner, outer, Center[inner, outer], params];>> <<};>> <> <> <<[] _ PW.IncludeInCell[top, CDRects.CreateRect[[size, 8], params.ringLayer]];>> <<[] _ CDCells.RepositionCell[top, NIL];>> <> <<[cell, status] _ SwitchBox[design, top, right, top, left, params];>> <<};>> END.