<> <> DIRECTORY Basics, Convert, Rope, SC, SCChanUtil, SCInstUtil, SCNetUtil, SCPrivate, SCPlaceUtil, SCSmash, SCWidthUtil, SCRowUtil, SCUtil, RTSets, TerminalIO; SCPlaceImproveImpl: CEDAR PROGRAM IMPORTS Convert, Rope, SC, SCChanUtil, SCInstUtil, SCNetUtil, SCPlaceUtil, SCRowUtil, SCWidthUtil, SCSmash, SCUtil, TerminalIO EXPORTS SCPrivate SHARES SC = { debug: BOOLEAN _ FALSE; PosResult: TYPE = RECORD[ area, channelWidth, wireLength: SC.Number, numFts: INT]; PlaceResult: TYPE = RECORD[ area, channelWidth, wireLength: SC.Number, numFts: INT]; WritePosResult: PROCEDURE [header: Rope.ROPE, Result: PosResult] = { -- write the results TerminalIO.WriteRope[header]; TerminalIO.WriteRope[Rope.Cat[" area: ", Convert.RopeFromInt[Result.area]]]; TerminalIO.WriteRope[Rope.Cat[", channelWidth: ", Convert.RopeFromInt[Result.channelWidth]]]; TerminalIO.WriteRope[Rope.Cat["\n wireLength: ", Convert.RopeFromInt[Result.wireLength]]]; TerminalIO.WriteRope[Rope.Cat[", numFts: ", Convert.RopeFromInt[Result.numFts], "\n"]]}; ComparePosResult: PROCEDURE [result1, result2: PosResult] RETURNS [FirstRelationSecond: Basics.Comparison] = { IF result1.area < result2.area THEN FirstRelationSecond _ less ELSE IF result1.area > result2.area THEN FirstRelationSecond _ greater ELSE IF result1.channelWidth < result2.channelWidth THEN FirstRelationSecond _ less ELSE IF result1.channelWidth > result2.channelWidth THEN FirstRelationSecond _ greater ELSE IF result1.wireLength < result2.wireLength THEN FirstRelationSecond _ less ELSE IF result1.wireLength > result2.wireLength THEN FirstRelationSecond _ greater ELSE IF result1.numFts < result2.numFts THEN FirstRelationSecond _ less ELSE IF result1.numFts > result2.numFts THEN FirstRelationSecond _ greater ELSE FirstRelationSecond _ equal}; -- they are equal ComparePlaceResult: PROCEDURE [result1, result2: PlaceResult] RETURNS [FirstRelationSecond: Basics.Comparison] = BEGIN IF result1.area < result2.area THEN FirstRelationSecond _ less ELSE IF result1.area > result2.area THEN FirstRelationSecond _ greater ELSE IF result1.channelWidth < result2.channelWidth THEN FirstRelationSecond _ less ELSE IF result1.channelWidth > result2.channelWidth THEN FirstRelationSecond _ greater ELSE IF result1.wireLength < result2.wireLength THEN FirstRelationSecond _ less ELSE IF result1.wireLength > result2.wireLength THEN FirstRelationSecond _ greater ELSE IF result1.numFts < result2.numFts THEN FirstRelationSecond _ less ELSE IF result1.numFts > result2.numFts THEN FirstRelationSecond _ greater ELSE FirstRelationSecond _ equal; -- they are equal END; -- ComparePlaceResult DoWidths: PROCEDURE [handle: SC.Handle, doChanWidth: SCPrivate.ChanSet, doSideWidth: SCPrivate.LRSideSet, doRowWidth: SCPrivate.RowSet, fom: SCPrivate.FomType] RETURNS [wireLength: SC.Number _ 0] = { EachRow: SCRowUtil.EachRowProc = { IF doRowWidth[(row)-1] THEN SCInstUtil.LgOffsets[handle, row, 0, 0]}; EachRowChan: SCChanUtil.EachRowChanProc = { IF doChanWidth[(chan )-1] THEN [rowChan.chanWidth, rowChan.wireLength] _ SCWidthUtil.GetChanWidth[handle, rowChan, fom, TRUE]; wireLength _ wireLength + layoutData.rowChans.chans[chan].wireLength}; EachSideChan: SCChanUtil.EachSideChanProc = { IF doSideWidth[LOOPHOLE[lrSide, INTEGER]] THEN { sideChan: SCPrivate.SideChan _ layoutData.sideChans[lrSide]; [sideChan.sideChanWidth, sideChan.wireLength] _ SCWidthUtil.GetSideWidth[handle, lrSide, fom]}; wireLength _ wireLength + sideChan.wireLength}; layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; [] _ SCRowUtil.EnumerateRows[handle, EachRow]; [] _ SCChanUtil.EnumerateRowChans[handle, EachRowChan]; [] _ SCChanUtil.EnumerateSideChans[handle, EachSideChan]}; <> ChosRow: PROCEDURE[handle: SC.Handle, rowIndex: SCPrivate.ZMaxRowSr] RETURNS[rowToDo: SCPrivate.LgRow, doUpper, doLower: BOOLEAN] = { layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; lgRows: SCPrivate.LgRows _ layoutData.lgRows; row: SCPrivate.ZMaxRowSr; SELECT TRUE FROM layoutData.bpRows[top].fnlBpFxd AND layoutData.bpRows[bottom].fnlBpFxd => {IF (rowIndex MOD 2) # 0 THEN row _ (lgRows.count+1) /2 - (rowIndex-1) /2 ELSE row _ (lgRows.count+1) /2 + rowIndex /2; doUpper _ doLower _ TRUE}; layoutData.bpRows[top].fnlBpFxd => {row _ lgRows.count - rowIndex + 1; doUpper _ TRUE; doLower _ FALSE}; layoutData.bpRows[bottom].fnlBpFxd => {row _ rowIndex; doUpper _ FALSE; doLower _ TRUE}; ENDCASE => {IF (rowIndex MOD 2) # 0 THEN row _ (lgRows.count+1) /2 - (rowIndex-1) /2 ELSE row _ (lgRows.count+1) /2 + rowIndex /2; IF row = (lgRows.count+1) /2 THEN {doUpper _ TRUE; doLower _ TRUE} ELSE IF row < (lgRows.count+1) /2 THEN {doUpper _ TRUE; doLower _ FALSE} ELSE {doUpper _ FALSE; doLower _ TRUE}}; rowToDo _ lgRows.rows[row]}; <> PosImproveRow: PROCEDURE [handle: SC.Handle, lgRow: SCPrivate.LgRow, doUpper, doLower: BOOLEAN, whichFom: SCPrivate.FomType] RETURNS [goodExch: INT _ 0] = { layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; structureData: SCPrivate.StructureData _ NARROW[handle.structureData]; lgRows: SCPrivate.LgRows _ layoutData.lgRows; row: SCPrivate.MaxRowSr _ lgRow.rowNum; rowChans: SCPrivate.RowChans _ layoutData.rowChans; lowerChan: SCPrivate.RowChan _ rowChans.chans[row]; upperChan: SCPrivate.RowChan _ rowChans.chans[row+1]; numFts: INT _ structureData.instances.numFts; oldLowChWidth, oldUpChWidth, oldLowWireLength, oldUpWireLength: SC.Number; oldResult: PosResult; TrialInterchange: SCRowUtil.EachInstProc = { nextPos: SCPrivate.MaxPosSr _ pos + 1; lowChWidth, upChWidth, upWireLength, lowWireLength: SC.Number; newResult: PosResult; SCPlaceUtil.ExchPosRow[handle, pos, nextPos, row]; [lowChWidth, lowWireLength] _ SCWidthUtil.GetChanWidth[handle, lowerChan, whichFom, doLower]; [upChWidth, upWireLength] _ SCWidthUtil.GetChanWidth[handle, upperChan, whichFom, doUpper]; newResult _ PosResult[(lowChWidth + upChWidth) * lgRows.maxRowWidth, (lowChWidth + upChWidth), (lowWireLength + upWireLength), numFts]; IF debug THEN WritePosResult[" trial result: ", newResult]; SELECT ComparePosResult[newResult, oldResult] FROM less => { -- strict improvement, thats good IF debug THEN TerminalIO.WriteRope[" accept improvement\n"]; lowerChan.chanWidth _ lowChWidth; upperChan.chanWidth _ upChWidth; oldResult _ newResult; goodExch _ goodExch + 1}; equal => { -- neutral improvement, take it IF debug THEN TerminalIO.WriteRope[" accept neutral exchange\n"]; lowerChan.chanWidth _ lowChWidth; upperChan.chanWidth _ upChWidth; oldResult _ newResult}; greater => { -- this change made it worse, restore old placement IF debug THEN WritePosResult[" restore old result: ", oldResult]; SCPlaceUtil.ExchPosRow[handle, pos, nextPos, row]}; ENDCASE}; IF lgRow.nLgsOnRow > 0 AND ~lgRow.fnlLgFxd AND (doUpper OR doLower) THEN { TerminalIO.WriteRope[Rope.Cat[" improve row ", Convert.RopeFromInt[row], ", "]]; [oldLowChWidth, oldLowWireLength] _ SCWidthUtil.GetChanWidth[handle, lowerChan, whichFom, doLower]; [oldUpChWidth, oldUpWireLength] _ SCWidthUtil.GetChanWidth[handle, upperChan, whichFom, doUpper]; oldResult _ PosResult[(oldLowChWidth + oldUpChWidth) * lgRows.maxRowWidth, (oldLowChWidth + oldUpChWidth), (oldLowWireLength + oldUpWireLength), numFts]; IF debug THEN WritePosResult["\n original logic result: ", oldResult]; [] _ SCRowUtil.EnumerateInstsOnRow[handle, row, 1, MAX[0, lgRow.nLgsOnRow-1], TrialInterchange]; TerminalIO.WriteRope[Rope.Cat[Convert.RopeFromInt[goodExch], " good exchanges\n"]]}}; <> PosImproveLeftRight: PROCEDURE[handle: SC.Handle, side: SC.Side, whichFom: SCPrivate.FomType] RETURNS [goodExch: INT _ 0] = { layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; structureData: SCPrivate.StructureData _ NARROW[handle.structureData]; lgRows: SCPrivate.LgRows _ layoutData.lgRows; bpRow: SCPrivate.BpRow _ layoutData.bpRows[side]; sideChan: SCPrivate.SideChan _ layoutData.sideChans[side]; wireLength: SC.Number; oldResult: PlaceResult; TrialInterchange: SCRowUtil.EachInstProc = { doChanWidth: SCPrivate.ChanSet _ RTSets.RTMdSetEmpty; doRowWidth: SCPrivate.ChanSet _ RTSets.RTMdSetEmpty; doSideWidth: SCPrivate.LRSideSet _ RTSets.RTSmSetEmpty; nextPos: SCPrivate.MaxPosSr _ pos +1; newWireLength: SC.Number; newResult: PlaceResult; nets: SCPrivate.NetList _ SCNetUtil.NetsOnInst[LIST[bpRow.bpsOnSide[pos], bpRow.bpsOnSide[nextPos]]]; [doChanWidth, doSideWidth, doRowWidth] _ SCSmash.RemoveNetsWFts[handle, nets, TRUE, doChanWidth, doSideWidth, doRowWidth]; SCPlaceUtil.ExchPosSide[handle, pos, nextPos, side]; [doChanWidth, doSideWidth, doRowWidth] _ SCSmash.SmashNets[handle, nets, FALSE, doChanWidth, doSideWidth, doRowWidth]; newWireLength _ DoWidths[handle, doChanWidth, doSideWidth, doRowWidth, whichFom]; [lgRows.maxRowWidth, lgRows.numMaxRows] _ SCRowUtil.FindMaxRow[handle]; SCInstUtil.AsgnChanPos[handle]; newResult _ PlaceResult[layoutData.totWidth * layoutData.totHeight, layoutData.sideChans[side].sideChanWidth, newWireLength, structureData.instances.numFts]; IF debug THEN WritePosResult[" trial result: ", newResult]; SELECT ComparePlaceResult[newResult, oldResult] FROM less => { -- strict improvement, thats good IF debug THEN TerminalIO.WriteRope[" accept improvement\n"]; wireLength _ newWireLength; oldResult _ newResult; goodExch _ goodExch + 1}; equal => { -- neutral exchange, take it IF debug THEN TerminalIO.WriteRope[" accept neutral exchange\n"]; wireLength _ newWireLength; oldResult _ newResult}; greater => { -- this change made it worse, restore old placement IF debug THEN WritePosResult[" restore old result: ", oldResult]; [doChanWidth, doSideWidth, doRowWidth] _ SCSmash.RemoveNetsWFts[handle, nets, FALSE, RTSets.RTMdSetEmpty, RTSets.RTSmSetEmpty, RTSets.RTMdSetEmpty]; SCPlaceUtil.ExchPosSide[handle, pos, nextPos, side]; [doChanWidth, doSideWidth, doRowWidth] _ SCSmash.RestoreNetsWFts[handle, nets, doChanWidth, doSideWidth, doRowWidth]; wireLength _ DoWidths[handle, doChanWidth, doSideWidth, doRowWidth, whichFom]; [lgRows.maxRowWidth, lgRows.numMaxRows] _ SCRowUtil.FindMaxRow[handle]; SCInstUtil.AsgnChanPos[handle]}; ENDCASE}; IF ~ bpRow.fnlBpFxd THEN { TerminalIO.WriteRope[Rope.Cat[" improve ", SCRowUtil.sideName[side], " side, "]]; SCWidthUtil.AllChanWidths[handle, whichFom]; wireLength _ DoWidths[handle, RTSets.RTMdSetEmpty, RTSets.RTSmSetEmpty, RTSets.RTMdSetEmpty, whichFom]; [lgRows.maxRowWidth, lgRows.numMaxRows] _ SCRowUtil.FindMaxRow[handle]; SCInstUtil.AsgnChanPos[handle]; oldResult _ PlaceResult[layoutData.totWidth * layoutData.totHeight, sideChan.sideChanWidth, wireLength, structureData.instances.numFts]; IF debug THEN WritePosResult[Rope.Cat["\n original ", SCRowUtil.sideName[side] ," result: "], oldResult]; [] _ SCRowUtil.EnumerateInstsOnSide[handle, side, 1, MAX[0, bpRow.nBpsOnSide -1], TrialInterchange]; TerminalIO.WriteRope[Rope.Cat[Convert.RopeFromInt[goodExch], " good exchanges\n"]]; SCWidthUtil.AllChanWidths[handle, areaFom]}}; <> PosImproveTopBot: PROCEDURE[handle: SC.Handle, side: SC.Side, whichFom: SCPrivate.FomType] RETURNS [goodExch: INT _ 0] = { layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; structureData: SCPrivate.StructureData _ NARROW[handle.structureData]; lgRows: SCPrivate.LgRows _ layoutData.lgRows; bpRow: SCPrivate.BpRow _ layoutData.bpRows[side]; rowChans: SCPrivate.RowChans _ layoutData.rowChans; numFts: INT _ structureData.instances.numFts; oldChWidth, oldWireLength: SC.Number; oldResult: PosResult; chan: SCPrivate.RowChan _ SELECT side FROM top => rowChans.chans[rowChans.count], bottom => rowChans.chans[1], ENDCASE => SC.Error[programmingError, "Invalid side in Placement Improvement"]; TrialInterchange: SCRowUtil.EachInstProc = { nextPos: SCPrivate.MaxPosSr _ pos + 1; chWidth, wireLength: SC.Number; newResult: PosResult; SCPlaceUtil.ExchPosSide[handle, pos, nextPos, side]; [chWidth, wireLength] _ SCWidthUtil.GetChanWidth[handle, chan, whichFom, TRUE]; newResult _ PosResult[chWidth * lgRows.maxRowWidth, chWidth, wireLength, numFts]; IF debug THEN WritePosResult[" trial result: ", newResult]; SELECT ComparePosResult[newResult, oldResult] FROM less => { -- strict improvement, thats good IF debug THEN TerminalIO.WriteRope[" accept improvement\n"]; chan.chanWidth _ chWidth; oldResult _ newResult; goodExch _ goodExch + 1}; equal => { -- neutral exchange, take what you can get IF debug THEN TerminalIO.WriteRope[" accept neutral exchange\n"]; chan.chanWidth _ chWidth; oldResult _ newResult}; greater => { -- this change made it worse, restore old placement IF debug THEN WritePosResult[" restore old result: ", oldResult]; SCPlaceUtil.ExchPosSide[handle, pos, nextPos, side]}; ENDCASE}; IF ~ bpRow.fnlBpFxd THEN { TerminalIO.WriteRope[Rope.Cat[" improve ", SCRowUtil.sideName[side], " side, "]]; [oldChWidth, oldWireLength] _ SCWidthUtil.GetChanWidth[handle, chan, whichFom, TRUE]; oldResult _ PosResult[oldChWidth * lgRows.maxRowWidth, oldChWidth, oldWireLength, numFts]; IF debug THEN WritePosResult[Rope.Cat["\n original ", SCRowUtil.sideName[side]," result: "], oldResult]; [] _ SCRowUtil.EnumerateInstsOnSide[handle, side, 1, MAX[0, bpRow.nBpsOnSide-1], TrialInterchange]; TerminalIO.WriteRope[Rope.Cat[Convert.RopeFromInt[goodExch], " good exchanges\n"]]}}; PosImprove: PUBLIC PROCEDURE [handle: SC.Handle, whichFom: SCPrivate.FomType, maxCycles: INT] = { layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; lgRows: SCPrivate.LgRows _ layoutData.lgRows; bpRows: SCPrivate.BpRows _ layoutData.bpRows; startArea: SC.Number; numCycles: INT _ 0; [lgRows.maxRowWidth, lgRows.numMaxRows] _ SCRowUtil.FindMaxRow[handle]; SCWidthUtil.AllChanWidths[handle, areaFom]; SCInstUtil.AsgnChanPos[handle]; startArea _ SCUtil.WriteResults["Position improvement\n starting area:", handle, 0]; DO goodExch: INT _ 0; goodTopExch, goodBottomExch, goodRightExch, goodLeftExch: INT; EachRow: SCRowUtil.EachRowProc = { rowToDo: SCPrivate.LgRow; doUpper, doLower: BOOLEAN; [rowToDo, doUpper, doLower] _ ChosRow[handle, row]; goodExch _ goodExch + PosImproveRow[handle, rowToDo, doUpper, doLower, whichFom]}; IF numCycles >= maxCycles THEN EXIT; <> goodLeftExch _ PosImproveLeftRight[handle, left, whichFom]; goodRightExch _ PosImproveLeftRight[handle, right, whichFom]; SCInstUtil.AsgnChanPos[handle]; [] _ SCRowUtil.EnumerateRows[handle, EachRow]; <> goodTopExch _ PosImproveTopBot[handle, top, whichFom]; goodBottomExch _ PosImproveTopBot[handle, bottom, whichFom]; IF goodExch + goodLeftExch + goodRightExch + goodTopExch + goodBottomExch <= 0 THEN EXIT; SCInstUtil.AsgnChanPos[handle]; numCycles _ numCycles + 1; ENDLOOP; SCInstUtil.AllOffsets[handle]; [lgRows.maxRowWidth, lgRows.numMaxRows] _ SCRowUtil.FindMaxRow[handle]; SCWidthUtil.AllChanWidths[handle, areaFom]; SCInstUtil.AsgnChanPos[handle]; [] _ SCUtil.WriteResults["End position improvement\n ending area:", handle, startArea]; IF debug THEN SCPlaceUtil.WriteCurPlace[handle]}; -- PosImprove <> OrientImproveRow: PROCEDURE [handle: SC.Handle, lgRow: SCPrivate.LgRow, doUpper, doLower: BOOLEAN, whichFom: SCPrivate.FomType] RETURNS [goodExch: INT _ 0] = { layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; structureData: SCPrivate.StructureData _ NARROW[handle.structureData]; lgRows: SCPrivate.LgRows _ layoutData.lgRows; row: SCPrivate.MaxRowSr _ lgRow.rowNum; rowChans: SCPrivate.RowChans _ layoutData.rowChans; lowerChan: SCPrivate.RowChan _ rowChans.chans[row]; upperChan: SCPrivate.RowChan _ rowChans.chans[row+1]; numFts: INT _ structureData.instances.numFts; oldLowChWidth, oldUpChWidth, oldLowWireLength, oldUpWireLength: SC.Number; oldResult: PosResult; TrialInterchange: SCRowUtil.EachInstProc = { lowChWidth, upChWidth, upWireLength, lowWireLength: SC.Number; newResult: PosResult; IF instance.fnlOrien = 0 THEN { SCPlaceUtil.ReverseOrientation[instance]; [lowChWidth, lowWireLength] _ SCWidthUtil.GetChanWidth[handle, lowerChan, whichFom, doLower]; [upChWidth, upWireLength] _ SCWidthUtil.GetChanWidth[handle, upperChan, whichFom, doUpper]; newResult _ PosResult[(lowChWidth + upChWidth) * lgRows.maxRowWidth, (lowChWidth + upChWidth), (lowWireLength + upWireLength), numFts]; IF debug THEN WritePosResult[" trial result: ", newResult]; SELECT ComparePosResult[newResult, oldResult] FROM less => { -- strict improvement, thats good IF debug THEN TerminalIO.WriteRope[" accept improvement\n"]; lowerChan.chanWidth _ lowChWidth; upperChan.chanWidth _ upChWidth; oldResult _ newResult; goodExch _ goodExch + 1}; equal => { -- neutral improvement, take it IF debug THEN TerminalIO.WriteRope[" accept neutral exchange\n"]; lowerChan.chanWidth _ lowChWidth; upperChan.chanWidth _ upChWidth; oldResult _ newResult}; greater => { -- this change made it worse, restore old placement IF debug THEN WritePosResult[" restore old result: ", oldResult]; SCPlaceUtil.ReverseOrientation[instance]}; ENDCASE}}; IF lgRow.nLgsOnRow > 0 AND (doUpper OR doLower) THEN { TerminalIO.WriteRope[Rope.Cat[" improve orientation on row ", Convert.RopeFromInt[row], ", "]]; [oldLowChWidth, oldLowWireLength] _ SCWidthUtil.GetChanWidth[handle, lowerChan, whichFom, doLower]; [oldUpChWidth, oldUpWireLength] _ SCWidthUtil.GetChanWidth[handle, upperChan, whichFom, doUpper]; oldResult _ PosResult[(oldLowChWidth + oldUpChWidth) * lgRows.maxRowWidth, (oldLowChWidth + oldUpChWidth), (oldLowWireLength + oldUpWireLength), numFts]; IF debug THEN WritePosResult[" original result: ", oldResult]; [] _ SCRowUtil.EnumerateAllInstsOnRow[handle, row, TrialInterchange]; TerminalIO.WriteRope[Rope.Cat[Convert.RopeFromInt[goodExch], " good exchanges\n"]]}}; OrientImprove: PUBLIC PROCEDURE [handle: SC.Handle, whichFom: SCPrivate.FomType, maxCycles: INT] = { layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; lgRows: SCPrivate.LgRows _ layoutData.lgRows; startArea: SC.Number; numCycles: INT _ 0; [lgRows.maxRowWidth, lgRows.numMaxRows] _ SCRowUtil.FindMaxRow[handle]; SCWidthUtil.AllChanWidths[handle, areaFom]; SCInstUtil.AsgnChanPos[handle]; startArea _ SCUtil.WriteResults["Orientation improvement\n starting area:", handle, 0]; DO EachRow: SCRowUtil.EachRowProc = { rowToDo: SCPrivate.LgRow; doUpper, doLower: BOOLEAN; [rowToDo, doUpper, doLower] _ ChosRow[handle, row]; goodExch _ OrientImproveRow[handle, rowToDo, doUpper, doLower, whichFom]}; goodExch: INT _ 0; IF numCycles >= maxCycles THEN EXIT; SCInstUtil.AsgnChanPos[handle]; [] _ SCRowUtil.EnumerateRows[handle, EachRow]; IF goodExch <= 0 THEN EXIT; SCInstUtil.AsgnChanPos[handle]; numCycles _ numCycles + 1; ENDLOOP; SCInstUtil.AllOffsets[handle]; [lgRows.maxRowWidth, lgRows.numMaxRows] _ SCRowUtil.FindMaxRow[handle]; SCWidthUtil.AllChanWidths[handle, areaFom]; SCInstUtil.AsgnChanPos[handle]; [] _ SCUtil.WriteResults["End orientation improvement\n ending area:", handle, startArea]; IF debug THEN SCPlaceUtil.WriteCurPlace[handle]}; -- PosImprove }.