DIRECTORY IO, RTBasic, SC, SCChanUtil, SCInstUtil, SCNetUtil, SCPrivate, SCRowUtil, SCPlaceUtil, Rope, RTSets, SCSmash, SCUtil, SCWidthUtil, TerminalIO; SCSmashImpl: CEDAR PROGRAM IMPORTS IO, RTBasic, SC, SCChanUtil, SCInstUtil, SCNetUtil, SCWidthUtil, SCPlaceUtil, SCRowUtil, SCSmash, SCUtil, RTSets, TerminalIO EXPORTS SCSmash SHARES SC = { debug: BOOLEAN _ FALSE; GetGoodFtPos: PROC [net: SCPrivate.Net, row: SCPrivate.MaxRowSr, nLgsOnRow: SCPrivate.ZMaxPosSr] RETURNS [midPos: SCPrivate.MaxPosSr] = { minPos: SC.Number _ LAST[SC.Number]; maxPos: SC.Number _ FIRST[SC.Number]; EachPin: SCNetUtil.EachPinProc = { instance: SCPrivate.Instance _ netPin.instance; SELECT instance.whichClass FROM ft, logic => { SELECT instance.curRow FROM row, row+1, row-1 => { minPos _ MIN[minPos, instance.curPos]; maxPos _ MAX[maxPos, instance.curPos]}; ENDCASE; }; ENDCASE }; [] _ SCNetUtil.EnumeratePinsOnNet[net, EachPin]; IF minPos = LAST[SC.Number] AND maxPos = FIRST[SC.Number] THEN midPos _ (1+ nLgsOnRow)/2 -- no instances in channels near row ELSE { minPos _ SELECT minPos FROM < 1 => 1, > nLgsOnRow => nLgsOnRow+1, ENDCASE => minPos; maxPos _ SELECT maxPos FROM < 1 => 1, > nLgsOnRow => nLgsOnRow+1, ENDCASE => maxPos; midPos _ (minPos + maxPos)/2; }; }; AddFt: PROCEDURE[handle: SC.Handle, lgRow: SCPrivate.LgRow, net: SCPrivate.Net, leftOnChan, rightOnChan: SCPrivate.ChanSet] RETURNS [ftInst: SCPrivate.Instance] = { layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; lgRows: SCPrivate.LgRows _ layoutData.lgRows; bpRows: SCPrivate.BpRows _ layoutData.bpRows; row: SCPrivate.MaxRowSr _ lgRow.rowNum; savPos: SCPrivate.MaxPosSr _ 1; --savWireLength, wireLength: SC.Number; ftInst _ NewFt[handle, net, lgRow]; IF net.ftsOnRow[(row)-1] THEN SC.Error[programmingError, NIL]; net.ftsOnRow _ RTSets.RTMdSetUnion[net.ftsOnRow, RTSets.RTMdSetGenerateElement[(row)-1]]; --SCPlaceUtil.PutLgPos[handle, ftInst, lgRow.rowNum, savPos]; --savWireLength _ NetWireLength[handle, net, lgRow, leftOnChan, rightOnChan, --net.pins]; --[] _ SCRowUtil.EnumerateInstsOnRow[handle, row, 2, lgRow.nLgsOnRow, PosProc]; savPos _ GetGoodFtPos[net, row, lgRow.nLgsOnRow]; -- find a good (not best) position for better performance --SCPlaceUtil.RemvLgComp[handle, ftInst]; SCPlaceUtil.PutLgPos[handle, ftInst, row, savPos]}; DetermineExits: PROCEDURE[handle: SC.Handle, side: SCPrivate.LRSide, net: SCPrivate.Net] RETURNS [onChan: SCPrivate.ChanSet _ RTSets.RTMdSetEmpty] = { ChanExitProc: SCChanUtil.EachRowChanProc = { IF onChan[(chan) - 1] THEN AddExit[handle, rowChan, chanSide, net]}; layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; rowChans: SCPrivate.RowChans _ layoutData.rowChans; acBuses: SCPrivate.AcBuses _ layoutData.acBuses; chanSide: RTBasic.Side _ RTBasic.OtherSide[side]; instList: SCPrivate.InstanceList _ SCNetUtil.InstsOnNets[LIST[net]]; touchesChan: SCPrivate.ChanSet _ SCInstUtil.ChansForInsts[handle, instList]; net.rowExits[side] _ RTSets.RTMdSetEmpty; FOR pList: SCPrivate.NetPinsList _ net.pins, pList.rest WHILE pList # NIL DO instance: SCPrivate.Instance _ pList.first.instance; pin: SCPrivate.ObjectPin _ pList.first.pin; SELECT instance.whichClass FROM io => {IF net.feedThrusAllowed THEN { p: SCInstUtil.PinDescription _ SCInstUtil.PosOf[instance, pin]; IF instance.curSide = side AND instance.curPos > 0 AND p.sideOn = chanSide THEN { ChanProc: SCChanUtil.EachRowChanProc = { IF touchesChan[(chan)-1] THEN { SetMinMaxDists: PROCEDURE [] = {IF dist < minDist THEN {minDistChan _ chan; minDist _ dist}; IF chanPos > maxChanPos THEN {maxChan _ chan; maxChanPos _ chanPos}; IF chanPos < minChanPos THEN {minChan _ chan; minChanPos _ chanPos}}; chanPos: SC.Number _ rowChan.chanPos + rowChan.chanWidth/2; dist: SC.Number _ ABS[chanPos - holdBpPos]; layoutParms: SCPrivate.LayoutParms _ layoutData.layoutParms; useMaxRouteExits: BOOLEAN _ layoutParms.useMaxRouteExits; useInteriorChanExits: BOOLEAN _ layoutParms.useInteriorChanExits; SELECT TRUE FROM ~useMaxRouteExits AND ~useInteriorChanExits => SetMinMaxDists; useMaxRouteExits AND ~useInteriorChanExits => IF rowChan.routeType = maxRoute THEN SetMinMaxDists; ~useMaxRouteExits AND useInteriorChanExits => IF (1 < chan AND chan < rowChans.count) THEN SetMinMaxDists; useMaxRouteExits AND useInteriorChanExits => IF (1 < chan AND chan < rowChans.count) AND rowChan.routeType = maxRoute THEN SetMinMaxDists; ENDCASE}}; minDist, minChanPos: SC.Number _ LAST[INT]; maxChanPos: SC.Number _ -LAST[INT]; minDistChan, maxChan, minChan: SCPrivate.ZMaxChanSr _ 0; holdBpPos: SC.Number _ SCInstUtil.BpPos[handle, instance] + p.yPos; [] _ SCChanUtil.EnumerateRowChans[handle, ChanProc]; SELECT TRUE FROM holdBpPos > maxChanPos AND maxChan > 0 => onChan _ RTSets.RTMdSetUnion[onChan, RTSets.RTMdSetGenerateElement[(maxChan)-1]]; holdBpPos < minChanPos AND minChan > 0 => onChan _ RTSets.RTMdSetUnion[onChan, RTSets.RTMdSetGenerateElement[(minChan)-1]]; minDistChan > 0 => onChan _ RTSets.RTMdSetUnion[onChan, RTSets.RTMdSetGenerateElement[(minDistChan)-1]]; ENDCASE}}}; logic => {IF ~net.feedThrusAllowed THEN { chan: SCPrivate.ZMaxChanSr _ 0; pinSide: RTBasic.Side _ SCInstUtil.PosOf[instance, pin].sideOn; IF pinSide = bottom THEN chan _ instance.curRow ELSE IF pinSide = top THEN chan _ instance.curRow + 1; IF chan # 0 AND net.acBus.onSide = side THEN IF rowChans.chans[chan].routeType = maxRoute THEN onChan _ RTSets.RTMdSetUnion[onChan, RTSets.RTMdSetGenerateElement[(chan)-1]]}}; ENDCASE; ENDLOOP; [] _ SCChanUtil.EnumerateRowChans[handle, ChanExitProc]}; ConnectRows: PROCEDURE[handle: SC.Handle, net: SCPrivate.Net, onRow: SCPrivate.RowSet, leftOnChan, rightOnChan, inDoChans: SCPrivate.ChanSet, inDoRows: SCPrivate.RowSet] RETURNS [doChanWidth: SCPrivate.ChanSet, doRowWidths: SCPrivate.RowSet] = { layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; lgRows: SCPrivate.LgRows _ layoutData.lgRows; rowChans: SCPrivate.RowChans _ layoutData.rowChans; onChan: SCPrivate.ChanSet _ RTSets.RTMdSetUnion[leftOnChan, rightOnChan]; lRow: SCPrivate.ZMaxRowSr _ 1; uRow: SCPrivate.ZMaxRowSr _ lgRows.count; found: BOOLEAN _ FALSE; doRowWidths _ inDoRows; doChanWidth _ inDoChans; WHILE lRow <= lgRows.count AND NOT found DO IF onRow[(lRow)-1] OR onChan[(lRow)-1] THEN found _ TRUE ELSE lRow _ lRow + 1; ENDLOOP; found _ FALSE; WHILE uRow >= 1 AND ~found DO IF onRow[(uRow)-1] OR onChan[(uRow + 1)-1] THEN found _ TRUE ELSE uRow _ uRow -1; ENDLOOP; FOR row: SCPrivate.MaxRowSr IN [lRow .. uRow] DO IF ~onRow[(row)-1] THEN { [] _ AddFt[handle, lgRows.rows[row], net, leftOnChan, rightOnChan]; doRowWidths _ RTSets.RTMdSetUnion[doRowWidths, RTSets.RTMdSetGenerateElement[(row)-1]]; doChanWidth _ RTSets.RTMdSetUnion[doChanWidth, RTSets.RTMdSetAddElement[(row)-1, RTSets.RTMdSetGenerateElement[(row + 1)-1]]]}; ENDLOOP}; SmashNets: PUBLIC PROCEDURE[handle: SC.Handle, nets: SCPrivate.NetList, doWidths: BOOLEAN, inDoChans: SCPrivate.ChanSet, inDoSides: SCPrivate.LRSideSet, inDoRows: SCPrivate.RowSet] RETURNS [doChanWidths: SCPrivate.ChanSet, doSideWidths: SCPrivate.LRSideSet, doRowWidths: SCPrivate.RowSet] = { EachNet: SCNetUtil.EachNetProc = { onSide: SCPrivate.SideSet; onRow: SCPrivate.RowSet; leftOnChan, rightOnChan: SCPrivate.ChanSet _ RTSets.RTMdSetEmpty; instList: SCPrivate.InstanceList _ SCNetUtil.InstsOnNets[LIST[net]]; numInstances: SCPrivate.ZMaxInstanceSr _ SCInstUtil.NumInstsOnList[instList]; doChanWidths _ inDoChans; doSideWidths _ inDoSides; doRowWidths _ inDoRows; net.ftsOnRow _ RTSets.RTMdSetEmpty; RemvAllExits[handle, net, left]; RemvAllExits[handle, net, right]; IF numInstances >= 2 THEN { [onSide, onRow] _ SCRowUtil.RowsForInsts[instList]; IF onSide[LOOPHOLE[SC.Side[left], INTEGER]] OR ~net.feedThrusAllowed THEN {leftOnChan _ DetermineExits[handle, left, net]; doSideWidths _ RTSets.RTSmSetUnion[doSideWidths, RTSets.RTSmSetGenerateElement[LOOPHOLE[SCPrivate.LRSide[left], INTEGER]]]}; doChanWidths _ RTSets.RTMdSetUnion[doChanWidths, leftOnChan]; IF onSide[LOOPHOLE[SC.Side[right], INTEGER]] OR ~net.feedThrusAllowed THEN {rightOnChan _ DetermineExits[handle, right, net]; doSideWidths _ RTSets.RTSmSetUnion[doSideWidths, RTSets.RTSmSetGenerateElement[LOOPHOLE[SCPrivate.LRSide[right], INTEGER]]]}; doChanWidths _ RTSets.RTMdSetUnion[doChanWidths, rightOnChan]; IF net.feedThrusAllowed THEN { IF onSide[LOOPHOLE[SC.Side[bottom], INTEGER]] AND ~ onRow[(1)-1] THEN { [] _ AddFt[handle, lgRows.rows[1], net, leftOnChan, rightOnChan]; doRowWidths _ RTSets.RTMdSetUnion[doRowWidths, RTSets.RTMdSetGenerateElement[(1)-1]]; onRow _ RTSets.RTMdSetUnion[ RTSets.RTMdSetGenerateElement[(1)-1], onRow]; doChanWidths _ RTSets.RTMdSetUnion[ RTSets.RTMdSetUnion[doChanWidths, RTSets.RTMdSetGenerateElement[(1)-1]], RTSets.RTMdSetGenerateElement[(2)-1]]}; IF (onSide[LOOPHOLE[SC.Side[top], INTEGER]]) AND ~onRow[(lgRows.count)-1] THEN { [] _ AddFt[handle, lgRows.rows[lgRows.count], net, leftOnChan, rightOnChan]; doRowWidths _ RTSets.RTMdSetUnion[doRowWidths, RTSets.RTMdSetGenerateElement[(lgRows.count)-1]]; onRow _ RTSets.RTMdSetUnion[ RTSets.RTMdSetGenerateElement[(lgRows.count)-1], onRow]; doChanWidths _ RTSets.RTMdSetUnion[ RTSets.RTMdSetUnion[doChanWidths , RTSets.RTMdSetGenerateElement[(lgRows.count)-1]], RTSets.RTMdSetGenerateElement[(lgRows.count + 1)-1]]}; [doChanWidths, doRowWidths] _ ConnectRows[handle, net, onRow, leftOnChan, rightOnChan, doChanWidths, doRowWidths]; IF doWidths THEN { EachRow: SCRowUtil.EachRowProc = {IF doRowWidths[row - 1] THEN SCInstUtil.LgOffsets[handle, row, 0, 0]}; EachChan: SCChanUtil.EachRowChanProc = {IF doChanWidths[chan - 1] THEN [rowChan.chanWidth, rowChan.wireLength] _ SCWidthUtil.GetChanWidth[handle, rowChan, areaFom, TRUE]}; [] _ SCRowUtil.EnumerateRows[handle, EachRow]; [] _ SCChanUtil.EnumerateRowChans[handle, EachChan]}}}}; layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; lgRows: SCPrivate.LgRows _ layoutData.lgRows; FOR netLst: SCPrivate.NetList _ nets, netLst.rest WHILE netLst # NIL DO [] _ EachNet[netLst.first.netNum, netLst.first]; ENDLOOP; IF debug THEN {CheckExits[handle]; CheckFts[handle]}; }; SmashAllNets: PUBLIC PROCEDURE [handle: SC.Handle, doChanWidths: BOOLEAN] = { NetProc: SCNetUtil.EachNetProc = { [] _ SmashNets[handle, LIST[net], doChanWidths, RTSets.RTMdSetEmpty, RTSets.RTSmSetEmpty, RTSets.RTMdSetEmpty]}; layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; lgRows: SCPrivate.LgRows _ layoutData.lgRows; [] _ SCNetUtil.EnumerateNets[handle, NetProc]; SCInstUtil.AllOffsets[handle]; [lgRows.maxRowWidth, lgRows.numMaxRows] _ SCRowUtil.FindMaxRow[handle]; SCWidthUtil.AllChanWidths[handle, areaFom]; SCInstUtil.AsgnChanPos[handle]; [] _ SCUtil.WriteResults["End topological route\n estimated size:", handle, 0]}; RemoveSmash: PUBLIC PROCEDURE [handle: SC.Handle] = { NetProc: SCNetUtil.EachNetProc = { [] _ SCSmash.RemoveNetsWFts[handle, LIST[net], FALSE, RTSets.RTMdSetEmpty, RTSets.RTSmSetEmpty, RTSets.RTMdSetEmpty]}; TerminalIO.WriteRope["Remove topological route\n"]; [] _ SCNetUtil.EnumerateNets[handle, NetProc]; SCInstUtil.AllOffsets[handle]; TerminalIO.WriteRope["End remove topological route\n"]}; ReSmash: PUBLIC PROCEDURE [handle: SC.Handle, doChanWidths: BOOLEAN] = { RemoveSmash[handle]; SmashAllNets[handle, doChanWidths]}; NewFt: PUBLIC PROCEDURE[handle: SC.Handle, net: SCPrivate.Net, lgRow: SCPrivate.LgRow] RETURNS [ftInst: SCPrivate.Instance] = { parms: SCPrivate.Parms _ NARROW[handle.parms]; name: Rope.ROPE _ IO.PutFR["%g-%g", IO.rope[net.name], IO.int[lgRow.rowNum]]; ftInst _ SCInstUtil.DefineInstance[handle, name, parms.ftObject, NIL, NIL]; ftInst.ftNet _ net; SCNetUtil.AddConnection[handle, net, ftInst, parms.ftObject.pins.p[0], 0]; SCNetUtil.AddConnection[handle, net, ftInst, parms.ftObject.pins.p[1], 1]}; AddExit: PUBLIC PROCEDURE[handle: SC.Handle, rowChan: SCPrivate.RowChan, side: SC.Side, net: SCPrivate.Net] = { IF rowChan.chanNum = 0 THEN SC.Error[programmingError, NIL] ELSE { index: NAT _ rowChan.numExits[side] _ rowChan.numExits[side] + 1; net.rowExits[side] _ RTSets.RTMdSetUnion[net.rowExits[side], RTSets.RTMdSetGenerateElement[(rowChan.chanNum)-1]]; rowChan.exits[side][index].net _ net; rowChan.exits[side][index].pos _ 0; rowChan.exits[side][index].layer _ handle.rules.rowRules.trunkLayer}}; RemvAllExits: PUBLIC PROCEDURE[handle: SC.Handle, net: SCPrivate.Net, lRSide: SCPrivate.LRSide] = { ChanProc: SCChanUtil.EachRowChanProc = { RemoveExit[handle, net, rowChan, lRSide]}; [] _ SCChanUtil.EnumerateRowChans[handle, ChanProc]}; RemoveExit: PUBLIC PROCEDURE[handle: SC.Handle, net: SCPrivate.Net, rowChan: SCPrivate.RowChan, lrSide: SCPrivate.LRSide] = { ChanExitProc: SCChanUtil.EachExitProc = { IF exit.net # net THEN { index _ index + 1; rowChan.exits[lrSide][index] _ rowChan.exits[lrSide][exitNum]}}; index: SCPrivate.ZMaxExitsSr _ 0; net.rowExits[lrSide] _ RTSets.RTMdSetDifference[net.rowExits[lrSide], RTSets.RTMdSetGenerateElement[(rowChan.chanNum)-1]]; [] _ SCChanUtil.EnumerateExits[handle, rowChan, lrSide, ChanExitProc]; rowChan.numExits[lrSide] _ index}; RemoveNetsWFts: PUBLIC PROCEDURE[handle: SC.Handle, netLst: SCPrivate.NetList, save: BOOLEAN, inDoChans: SCPrivate.ChanSet, inDoSides: SCPrivate.LRSideSet, inDoRows: SCPrivate.RowSet] RETURNS [doChanWidths: SCPrivate.ChanSet, doSideWidths: SCPrivate.LRSideSet, doRowWidths: SCPrivate.RowSet] = { layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; globalRoute: SCSmash.GlobalRoute _ NEW[SCSmash.GlobalRouteRec]; layoutData.globalRoute _ globalRoute; doChanWidths _ inDoChans; doSideWidths _ inDoSides; doRowWidths _ inDoRows; IF save THEN {globalRoute.numFts _ globalRoute.numNets _ 0}; FOR nets: SCPrivate.NetList _ netLst, nets.rest WHILE nets # NIL DO EachInst: SCNetUtil.EachInstProc = { IF instance.whichClass = ft THEN { IF save THEN { IF globalRoute.numFts >= SCSmash.maxFtsSaved THEN SC.Error[noResource, NIL]; globalRoute.numFts _ globalRoute.numFts + 1; globalRoute.fts[globalRoute.numFts] _ NEW[SCSmash.FtDataRec _ [net, instance.curRow, instance.curPos]]; IF ~net.feedThrusAllowed THEN SC.Error[programmingError, NIL]}; doRowWidths _ RTSets.RTMdSetUnion[doRowWidths, RTSets.RTMdSetGenerateElement[(instance.curRow)-1]]; doChanWidths _ RTSets.RTMdSetUnion[ RTSets.RTMdSetUnion[doChanWidths, RTSets.RTMdSetGenerateElement[(instance.curRow)-1]], RTSets.RTMdSetGenerateElement[(instance.curRow + 1)-1]]; SCPlaceUtil.RemvLgComp[handle, instance]}}; EachChan: SCChanUtil.EachRowChanProc = { FOR lrSide: SCPrivate.LRSide IN SCPrivate.LRSide DO IF net.rowExits[lrSide][(chan)-1] THEN {doChanWidths _ RTSets.RTMdSetUnion[doChanWidths, RTSets.RTMdSetGenerateElement[(chan)-1]]; doSideWidths _ RTSets.RTSmSetUnion[doSideWidths , RTSets.RTSmSetGenerateElement[LOOPHOLE[lrSide, INTEGER]]]}; ENDLOOP}; net: SCPrivate.Net _ nets.first; [] _ SCNetUtil.EnumerateInstsOnNets[LIST[net], EachInst]; SCNetUtil.RemoveFtsOnNet[handle, net]; IF save THEN { IF globalRoute.numNets >= SCSmash.maxNetsSaved THEN SC.Error[noResource, NIL]; globalRoute.numNets _ globalRoute.numNets + 1; globalRoute.nets[globalRoute.numNets].net _ net; globalRoute.nets[globalRoute.numNets].exit[left] _ net.rowExits[left]; globalRoute.nets[globalRoute.numNets].exit[right] _ net.rowExits[right]}; [] _ SCChanUtil.EnumerateRowChans[handle, EachChan]; RemvAllExits[handle, net, left]; RemvAllExits[handle, net, right]; net.ftsOnRow _ RTSets.RTMdSetEmpty; ENDLOOP; IF debug THEN {CheckExits[handle]; CheckFts[handle]}; }; RestoreNetsWFts: PUBLIC PROCEDURE[handle: SC.Handle, netLst: SCPrivate.NetList, inDoChans: SCPrivate.ChanSet, inDoSides: SCPrivate.LRSideSet, inDoRows: SCPrivate.RowSet] RETURNS [doChanWidths : SCPrivate.ChanSet, doSideWidths: SCPrivate.LRSideSet, doRowWidths: SCPrivate.RowSet]= { ChanRowProc: SCRowUtil.EachRowProc = { IF doRowWidths[(row)-1] THEN SCInstUtil.LgOffsets[handle, row, 0, 0]}; CheckConnection: PROCEDURE[net: SCPrivate.Net, leftExitChan, rightExitChan: SCPrivate.RowChan] = { instList: SCPrivate.InstanceList _ SCNetUtil.InstsOnNets[LIST[net]]; onSide: SCPrivate.SideSet; onRow: SCPrivate.RowSet; [onSide, onRow] _ SCRowUtil.RowsForInsts[instList]; IF leftExitChan.chanNum = 1 OR rightExitChan.chanNum = 1 THEN { IF NOT (onSide[LOOPHOLE[SC.Side[bottom], INTEGER]] OR onRow[(1)-1]) THEN SC.Error[programmingError, NIL]} ELSE IF leftExitChan.chanNum = rowChans.count OR rightExitChan.chanNum = rowChans.count THEN { IF NOT (onSide[LOOPHOLE[SC.Side[top ], INTEGER]] OR onRow[(rowChans.count-1)-1]) THEN SC.Error[programmingError, NIL]}; IF 1 < leftExitChan.chanNum AND leftExitChan.chanNum < rowChans.count THEN { IF NOT (onRow[(leftExitChan.chanNum) - 1] OR onRow[(leftExitChan.chanNum-1) - 1]) THEN SC.Error[programmingError, NIL]}; IF 1 < rightExitChan.chanNum AND rightExitChan.chanNum < rowChans.count THEN { IF NOT (onRow[(rightExitChan.chanNum)-1] OR onRow[(rightExitChan.chanNum-1)-1]) THEN SC.Error[programmingError, NIL]}}; layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; globalRoute: SCSmash.GlobalRoute _ NARROW[layoutData.globalRoute]; rowChans: SCPrivate.RowChans _ layoutData.rowChans; lgRows: SCPrivate.LgRows _ layoutData.lgRows; doChanWidths _ inDoChans; doSideWidths _ inDoSides; doRowWidths _ inDoRows; FOR ftIndex: SCSmash.ZMFtsSavedSr DECREASING IN [1 .. globalRoute.numFts] DO net: SCPrivate.Net _ globalRoute.fts[ftIndex].net; row: NAT _ globalRoute.fts[ftIndex].row; ftInst: SCPrivate.Instance _ NewFt[handle, net, lgRows.rows[row]]; IF ~net.feedThrusAllowed THEN SC.Error[programmingError, NIL]; SCPlaceUtil.PutLgPos[handle, ftInst, row, globalRoute.fts[ftIndex].pos]; doRowWidths _ RTSets.RTMdSetUnion[doRowWidths, RTSets.RTMdSetGenerateElement[(row)-1]]; doChanWidths _ RTSets.RTMdSetUnion[doChanWidths, RTSets.RTMdSetAddElement[(row)-1, RTSets.RTMdSetGenerateElement[(row + 1)-1]]]; ENDLOOP; [] _ SCRowUtil.EnumerateRows[handle, ChanRowProc]; FOR netIndex: SCSmash.MNetsSavedSr DECREASING IN [1 .. globalRoute.numNets] DO ChanRowProc: SCChanUtil.EachRowChanProc = { FOR lrSide: SC.Side IN SCPrivate.LRSide DO RemoveExit[handle, net, rowChan, lrSide]; IF globalRoute.nets[netIndex].exit[lrSide][(chan)-1] THEN { exitChan[lrSide] _ rowChan; AddExit[handle, rowChan, lrSide, net]; doChanWidths _ RTSets.RTMdSetUnion[doChanWidths, RTSets.RTMdSetGenerateElement[(chan)-1]]; doSideWidths _ RTSets.RTSmSetUnion[doSideWidths , RTSets.RTSmSetGenerateElement[LOOPHOLE[lrSide, INTEGER]]]}; ENDLOOP}; exitChan: ARRAY SCPrivate.LRSide OF SCPrivate.RowChan _ [NIL, NIL]; net: SCPrivate.Net _ globalRoute.nets[netIndex].net; net.rowExits[left] _ RTSets.RTMdSetEmpty; net.rowExits[right] _ RTSets.RTMdSetEmpty; [] _ SCChanUtil.EnumerateRowChans[handle, ChanRowProc]; CheckConnection[net, exitChan[left], exitChan[right]]; ENDLOOP; IF debug THEN {CheckExits[handle]; CheckFts[handle]}; }; CheckExits: PUBLIC PROCEDURE [handle: SC.Handle] = { NetProc: SCNetUtil.EachNetProc = { ChanExitProc: SCChanUtil.EachRowChanProc = { SideProc: SCChanUtil.EachSideChanProc = { ExitProc: SCChanUtil.EachExitProc = { IF exit.net = net THEN quit _ TRUE}; exitPresent: BOOLEAN _ RTSets.RTMdSetIsSubset[ RTSets.RTMdSetGenerateElement[chan - 1], net.rowExits[lrSide]]; found: BOOLEAN _ SCChanUtil.EnumerateExits[handle, rowChan, lrSide, ExitProc]; IF exitPresent AND ~found OR ~exitPresent AND found THEN SC.Error[programmingError, NIL]}; [] _ SCChanUtil.EnumerateSideChans[handle, SideProc]}; [] _ SCChanUtil.EnumerateRowChans[handle, ChanExitProc]}; [] _ SCNetUtil.EnumerateNets[handle, NetProc]}; CheckFts: PUBLIC PROCEDURE [handle: SC.Handle] = { EachNet: SCNetUtil.EachNetProc = {CheckFtsOnNet[handle, net]}; [] _ SCNetUtil.EnumerateNets[handle, EachNet]}; CheckFtsOnNet: PUBLIC PROCEDURE[handle: SC.Handle, net: SCPrivate.Net] = { EachRow: SCRowUtil.EachRowProc = { PosProc: SCRowUtil.EachInstProc = { IF instance.whichClass = ft THEN { netPin1: SCPrivate.Net _ instance.pinNets.n[0].net; netPin2: SCPrivate.Net _ instance.pinNets.n[1].net; IF netPin1 = NIL OR netPin2 = NIL OR netPin1 # netPin2 THEN SC.Error[programmingError, NIL]; IF netPin1 = net THEN { IF ftsOnRow[row-1] THEN SC.Error[programmingError, NIL]; ftsOnRow _ RTSets.RTMdSetUnion[ftsOnRow, RTSets.RTMdSetGenerateElement[(row)-1]]}}}; [] _ SCRowUtil.EnumerateAllInstsOnRow[handle, row, PosProc]}; ftsOnRow: SCPrivate.RowSet _ RTSets.RTMdSetEmpty; [] _ SCRowUtil.EnumerateRows[handle, EachRow]; IF ~RTSets.RTMdSetIsSame[ftsOnRow, net.ftsOnRow] THEN SC.Error[programmingError, NIL]}; StrippedAddFt: PROCEDURE[handle: SC.Handle, lgRow: SCPrivate.LgRow, net: SCPrivate.Net] = { layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; parms: SCPrivate.Parms _ NARROW[handle.parms]; IF net.ftsOnRow[(lgRow.rowNum)-1] THEN SC.Error[programmingError, NIL]; net.ftsOnRow _ RTSets.RTMdSetUnion[net.ftsOnRow, RTSets.RTMdSetGenerateElement[(lgRow.rowNum)-1]]; lgRow.size.p _ lgRow.size.p + parms.ftObject.size.p; lgRow.nFtsOnRow _ lgRow.nFtsOnRow + 1}; StrippedConnectRows: PROCEDURE[handle: SC.Handle, net: SCPrivate.Net, onRow: SCPrivate.RowSet, leftOnChan, rightOnChan: SCPrivate.ChanSet, sign: SC.Number, addFts: BOOLEAN] = { layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; lgRows: SCPrivate.LgRows _ layoutData.lgRows; rowChans: SCPrivate.RowChans _ layoutData.rowChans; onChan: SCPrivate.ChanSet _ RTSets.RTMdSetUnion[leftOnChan, rightOnChan]; uRow: SCPrivate.ZMaxRowSr _ lgRows.count; lRow: SCPrivate.ZMaxRowSr _ 1; found: BOOLEAN _ FALSE; WHILE lRow <= lgRows.count AND ~ found DO IF onRow[(lRow)-1] OR onChan[(lRow)-1] THEN found _ TRUE ELSE lRow _ lRow + 1; ENDLOOP; found _ FALSE; WHILE uRow >= 1 AND ~ found DO IF onRow[(uRow)-1] OR onChan[(uRow + 1)-1] THEN found _ TRUE ELSE uRow _ uRow - 1; ENDLOOP; IF lRow <= uRow THEN { numFts: INT _ sign*MAX[uRow - lRow, 0]; rowChans.totNetChans _ rowChans.totNetChans + numFts; IF onChan[lRow -1] THEN { rowChan: SCPrivate.RowChan _ layoutData.rowChans.chans[lRow]; rowChans.totNetChans _ rowChans.totNetChans + sign; rowChan.netChans _ rowChan.netChans + sign}; IF onChan[uRow -1] THEN { rowChan: SCPrivate.RowChan _ layoutData.rowChans.chans[uRow]; rowChans.totNetChans _ rowChans.totNetChans + sign; rowChan.netChans _ rowChan.netChans + sign}; FOR row: SCPrivate.ZMaxRowSr IN [lRow .. uRow] DO lgRow: SCPrivate.LgRow _ layoutData.lgRows.rows[row]; rowChan: SCPrivate.RowChan _ layoutData.rowChans.chans[row]; IF row # lRow THEN rowChan.netChans _ rowChan.netChans + sign; IF ~ onRow[(row)-1] AND addFts THEN StrippedAddFt[handle, lgRow, net]; ENDLOOP}}; StrippedSmashNets: PUBLIC PROCEDURE[handle: SC.Handle, nets: SCPrivate.NetList] = { layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; lgRows: SCPrivate.LgRows _ layoutData.lgRows; FOR netLst: SCPrivate.NetList _ nets, netLst.rest WHILE netLst # NIL DO net: SCPrivate.Net _ nets.first; onSide: SCPrivate.SideSet; onRow: SCPrivate.RowSet; leftOnChan, rightOnChan: SCPrivate.ChanSet _ RTSets.RTMdSetEmpty; instList: SCPrivate.InstanceList _ SCNetUtil.InstsOnNets[LIST[net]]; numInstances: SCPrivate.ZMaxInstanceSr _ SCInstUtil.NumInstsOnList[instList]; net.ftsOnRow _ RTSets.RTMdSetEmpty; RemvAllExits[handle, net, left]; RemvAllExits[handle, net, right]; IF numInstances >= 2 THEN { [onSide, onRow] _ SCRowUtil.RowsForInsts[instList]; IF onSide[LOOPHOLE[SC.Side[left], INTEGER]] OR ~net.feedThrusAllowed THEN leftOnChan _ DetermineExits[handle, left, net]; IF onSide[LOOPHOLE[SC.Side[right], INTEGER]] OR ~net.feedThrusAllowed THEN rightOnChan _ DetermineExits[handle, right, net]; IF net.feedThrusAllowed THEN { IF onSide[LOOPHOLE[SC.Side[bottom], INTEGER]] AND NOT onRow[(1)-1] THEN { StrippedAddFt[handle, lgRows.rows[1], net]; onRow _ RTSets.RTMdSetUnion[ RTSets.RTMdSetGenerateElement[(1)-1], onRow]}; IF (onSide[LOOPHOLE[SC.Side[top], INTEGER]]) AND NOT (onRow[(lgRows.count)-1]) THEN { StrippedAddFt[handle, lgRows.rows[lgRows.count], net]; onRow _ RTSets.RTMdSetUnion[ RTSets.RTMdSetGenerateElement[(lgRows.count)-1], onRow]}; StrippedConnectRows[handle, net, onRow, leftOnChan, rightOnChan, 1, TRUE]}}; ENDLOOP; }; StrippedSmashAllNets: PUBLIC PROCEDURE [handle: SC.Handle] = { NetProc: SCNetUtil.EachNetProc = { StrippedSmashNets[handle, LIST[net]]}; [] _ SCNetUtil.EnumerateNets[handle, NetProc]}; StrippedRemoveSmash: PUBLIC PROCEDURE [handle: SC.Handle] = { -- alter the smash of the nets NetProc: SCNetUtil.EachNetProc = { StrippedRemoveNetsWFts[handle, LIST[net], FALSE]}; ClearNetChans[handle]; [] _ SCNetUtil.EnumerateNets[handle, NetProc]}; StrippedRemoveNetsWFts: PUBLIC PROCEDURE[handle: SC.Handle, netLst: SCPrivate.NetList, save: BOOLEAN] = { layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; globalRoute: SCSmash.GlobalRoute _ NARROW[layoutData.globalRoute]; parms: SCPrivate.Parms _ NARROW[handle.parms]; IF save THEN -- save indicates whether current smash is to be saved {globalRoute.numFts _ 0; globalRoute.numNets _ 0}; FOR nets: SCPrivate.NetList _ netLst, nets.rest WHILE nets # NIL DO EachRow: SCRowUtil.EachRowProc = { IF net.ftsOnRow[row - 1] THEN { IF save THEN { IF globalRoute.numFts >= SCSmash.maxFtsSaved THEN SC.Error[noResource, NIL]; globalRoute.numFts _ globalRoute.numFts + 1; globalRoute.fts[globalRoute.numFts] _ NEW[SCSmash.FtDataRec _ [net, row, 0]]; IF globalRoute.numFts >= SCSmash.maxFtsSaved THEN SC.Error[noResource, NIL]}; lgRow.size.p _ lgRow.size.p - parms.ftObject.size.p; lgRow.nFtsOnRow _ lgRow.nFtsOnRow - 1; IF lgRow.nFtsOnRow < 0 OR lgRow.size.p < 0 THEN SC.Error[programmingError, NIL]}}; net: SCPrivate.Net _ nets.first; [] _ SCRowUtil.EnumerateRows[handle, EachRow]; IF save THEN { IF globalRoute.numNets >= SCSmash.maxNetsSaved THEN SC.Error[programmingError, NIL]; globalRoute.numNets _ globalRoute.numNets + 1; globalRoute.nets[globalRoute.numNets].net _ net; globalRoute.nets[globalRoute.numNets].exit[left] _ net.rowExits[left]; globalRoute.nets[globalRoute.numNets].exit[right] _ net.rowExits[right]}; RemvAllExits[handle, net, left]; RemvAllExits[handle, net, right]; net.ftsOnRow _ RTSets.RTMdSetEmpty; ENDLOOP}; StrippedRestoreNetsWFts: PUBLIC PROCEDURE[handle: SC.Handle] = { layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; globalRoute: SCSmash.GlobalRoute _ NARROW[layoutData.globalRoute]; lgRows: SCPrivate.LgRows _ layoutData.lgRows; FOR ftIndex: SCSmash.ZMFtsSavedSr DECREASING IN [1 .. globalRoute.numFts] DO net: SCPrivate.Net _ globalRoute.fts[ftIndex].net; row: NAT _ globalRoute.fts[ftIndex].row; lgRow: SCPrivate.LgRow _ lgRows.rows[row]; IF ~net.feedThrusAllowed THEN SC.Error[programmingError, NIL]; StrippedAddFt[handle, lgRow, net]; ENDLOOP; FOR netIndex: SCSmash.MNetsSavedSr DECREASING IN [1 .. globalRoute.numNets] DO ChanProc: SCChanUtil.EachRowChanProc = { FOR lrSide: SC.Side IN SCPrivate.LRSide DO RemoveExit[handle, net, rowChan, lrSide]; IF globalRoute.nets[netIndex].exit[lrSide][(rowChan.chanNum)-1] THEN {AddExit[handle, rowChan, lrSide, net]}; ENDLOOP}; net: SCPrivate.Net _ globalRoute.nets[netIndex].net; net.rowExits[left] _ RTSets.RTMdSetEmpty; net.rowExits[right] _ RTSets.RTMdSetEmpty; [] _ SCChanUtil.EnumerateRowChans[handle, ChanProc]; ENDLOOP; }; -- StrippedRestoreNetsWFts ModNetChans: PUBLIC PROCEDURE[handle: SC.Handle, nets: SCPrivate.NetList, sign: SC.Number] = { EachNet: SCNetUtil.EachNetProc = { onSide: SCPrivate.SideSet; onRow: SCPrivate.RowSet; leftOnChan: SCPrivate.ChanSet _ net.rowExits[left]; rightOnChan: SCPrivate.ChanSet _ net.rowExits[right]; instList: SCPrivate.InstanceList _ SCNetUtil.InstsOnNets[LIST[net]]; numInstances: SCPrivate.ZMaxInstanceSr _ SCInstUtil.NumInstsOnList[instList]; IF numInstances >= 2 THEN { [onSide, onRow] _ SCRowUtil.RowsForInsts[instList]; IF net.feedThrusAllowed THEN { IF onSide[LOOPHOLE[SC.Side[bottom], INTEGER]] AND ~ onRow[(1)-1] THEN onRow _ RTSets.RTMdSetUnion[ RTSets.RTMdSetGenerateElement[(1)-1], onRow]; IF onSide[LOOPHOLE[SC.Side[top], INTEGER]] AND ~ onRow[(lgRows.count)-1] THEN onRow _ RTSets.RTMdSetUnion[ RTSets.RTMdSetGenerateElement[(lgRows.count)-1], onRow]; StrippedConnectRows[handle, net, onRow, leftOnChan, rightOnChan, sign, FALSE]}}}; layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; lgRows: SCPrivate.LgRows _ layoutData.lgRows; [] _ SCNetUtil.EnumerateNets[handle, EachNet]}; ClearNetChans: PUBLIC PROCEDURE [handle: SC.Handle] = { EachChan: SCChanUtil.EachRowChanProc = {rowChan.netChans _ 0}; layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; layoutData.rowChans.totNetChans _ 0; [] _ SCChanUtil.EnumerateRowChans[handle, EachChan]}; }. R///StdCell/SCSmashImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Frank Bowers February 13, 1986 11:04:31 am PST add ft's on interior rows as required NetWireLength: PROCEDURE[handle: SC.Handle, net: SCPrivate.Net, lgRow: SCPrivate.LgRow, leftOnChan, rightOnChan: SCPrivate.ChanSet, pins: SCPrivate.NetPinsList] RETURNS [wireLength: SC.Number] = { compute wirelength of net in channels adjacent to row EachPin: SCNetUtil.EachPinProc = { instance: SCPrivate.Instance _ netPin.instance; p: SCInstUtil.PinDescription _ SCInstUtil.PosOf[instance, netPin.pin]; SELECT instance.whichClass FROM ft, logic => { IF instance.curRow = row AND p.sideOn = top THEN { pinPos: SC.Number _ lgRow.rowOrg.p + instance.offset + p.xPos; upMax _ MAX[upMax, pinPos]; upMin _ MIN[upMin, pinPos]} ELSE IF instance.curRow = row AND p.sideOn = bottom THEN { pinPos: SC.Number _ lgRow.rowOrg.p + instance.offset + p.xPos ; lowMax _ MAX[lowMax, pinPos]; lowMin _ MIN[lowMin, pinPos]} ELSE IF instance.curRow = row-1 AND p.sideOn = top THEN { pinPos: SC.Number _ lgRows.rows[row-1].rowOrg.p + instance.offset + p.xPos; lowMax _ MAX[lowMax, pinPos]; lowMin _ MIN[lowMin, pinPos]} ELSE IF instance.curRow = row + 1 AND p.sideOn = bottom THEN { pinPos: SC.Number _ lgRows.rows[row + 1].rowOrg.p + instance.offset + p.xPos; upMax _ MAX[upMax, pinPos]; upMin _ MIN[upMin, pinPos]}}; -- logic, ft pin io => { IF row = 1 AND instance.curSide = bottom AND p.sideOn = top THEN { pinPos: SC.Number _ bpRows[bottom].sideOrg.p + instance.offset + p.xPos; lowMax _ MAX[lowMax, pinPos]; lowMin _ MIN[lowMin, pinPos]} ELSE IF row = lgRows.count AND instance.curSide = top AND p.sideOn = bottom THEN { pinPos: SC.Number _ bpRows[top].sideOrg.p - instance.offset + p.xPos; upMax _ MAX[upMax, pinPos]; upMin _ MIN[upMin, pinPos]}}; -- bonding pad pin ENDCASE}; initialize the limits lowMax, upMax: SC.Number _ -LAST[INT]; lowMin, upMin: SC.Number _ LAST[INT]; row: SCPrivate.MaxRowSr _ lgRow.rowNum; run through the pins to find limits [] _ SCNetUtil.EnumeratePinsOnNet[net, EachPin]; now extend the ends for the side exits IF leftOnChan[(row)-1] THEN { lowMax _ MAX[lowMax, lgRows.horzRowOrg]; lowMin _ MIN[lowMin, lgRows.horzRowOrg]}; IF leftOnChan[(row + 1)-1] THEN { upMax _ MAX[upMax, lgRows.horzRowOrg]; upMin _ MIN[upMin, lgRows.horzRowOrg]}; IF rightOnChan[(row)-1] THEN { lowMax _ MAX[lowMax, lgRows.horzRowOrg + lgRows.maxRowWidth]; lowMin _ MIN[lowMin, lgRows.horzRowOrg + lgRows.maxRowWidth]}; IF rightOnChan[(row + 1)-1] THEN { upMax _ MAX[upMax, lgRows.horzRowOrg + lgRows.maxRowWidth]; upMin _ MIN[upMin, lgRows.horzRowOrg + lgRows.maxRowWidth]}; got extents on each adajacent channel, now compute wirelength wireLength _ 0; IF lowMax > lowMin THEN wireLength _ wireLength + lowMax - lowMin; IF upMax > upMin THEN wireLength _ wireLength + upMax - upMin}; AddFt PosProc: SCRowUtil.EachInstProc = { SCPlaceUtil.ExchPosRow[handle, pos-1, pos, row]; wireLength _ NetWireLength[handle, net, lgRow, leftOnChan, rightOnChan, net.pins]; IF wireLength < savWireLength THEN { -- strict improvement, thats good savWireLength _ wireLength; savPos _ pos}}; try new ft at rest of positions on row found best position, put ft there add side exits as required to net lists find preferred position for exit to side surface get position of instance on side find distance of port to closest existing channel determine channel to exit found channels to exit from, indicated in onChan find lowest row that needs ft find upper row that needs ft add fts to required rows between lrow and urow now update the channel widths add feedthrus to required rows alter the smash of the nets add ft to row width get a component entry for the ft, construct a new entry for instance construct and add an entry to net list for this instance add an exit to a channel remove all exits for net on a lRSide remove an exit for net on chan remove specified nets with fts save indicates whether current smash is to be saved now remove the ft run through the comps on this net now work on the exits save route data for specified nets make sure feed throughs are in proper channels RestoreNetsWFts first restore the feedthroughs find row widths now the channel exits check to make sure the net is connected audit the exits for consistancy audit the Fts on all nets for consistancy audit the Fts on net for consistancy error in connection of net more than one ft on row for this net on this row row data does not correspond to instance data add ft's on interior rows as required find lowest row that needs ft find upper row that needs ft add fts to required rows between lrow and urow add feedthrus to required rows SCRowUtil.AuditRowLengths}; remove specified nets with fts run through the rows fon this net now work on the exits restore route data for specified nets first restore the feedthroughs now the channel exits Κ9˜šœ™Icodešœ Οmœ1™Jšœžœ™Jšœžœ™—šžœžœžœžœ™:Jšœžœ5™?Jšœ žœ™Jšœ žœ™—šžœžœžœžœ™9JšœžœA™KJšœ žœ™Jšœ žœ™—šžœžœžœžœ™>JšœžœC™MJšœžœ™Jšœžœžœ ™/——šœ™šžœ žœžœžœ™BJšœžœ>™HJšœ žœ™Jšœ žœ™—š žœžœžœžœžœ™RJšœžœ;™EJšœžœ™Jšœžœžœ ™1——Jšžœ™ —J™—Jšœ™Jšœžœ žœžœ™&Jšœžœ žœžœ™%J™'J™Jšœ$™$Jšœ0™0J™Jšœ'™'šžœžœ™Jšœ žœ™(Jšœ žœ™)—šžœžœ™!Jšœžœ™&Jšœžœ™'—šžœžœ™Jšœ žœ1™=Jšœ žœ2™>—šžœžœ™"Jšœžœ0™;šœžœ1™™>Jšœ™Jšžœžœ+™BJšžœžœ*™?J™—Jšœ™šœ#™#Jšœ0™0šœR™RJ™—šžœžœ "™GJšœ+™+J™——Jšœ#žœ˜=Jšœ-˜-Jšœ-˜-J˜'Jšœ˜Jšœžœ˜'Jšœ#˜#Jšžœžœžœžœ˜>šœ1˜1Jšœ(˜(—Jšœ=˜=šœM˜MJšœ ˜ J˜—Jšœ'™'JšœO˜OJ™Jšœ"™"J™Jšœk˜kJšœ)˜)Jšœ4˜4—J˜šŸœž œ žœ4˜XJšžœ6˜=Jšœ(™(J˜Jšœ0™0šœ,˜,Jšžœžœ*˜DJ˜—Jšœ#žœ˜=Jšœ3˜3Jšœ0˜0Jšœ1˜1Jšœ9žœ˜DJšœL˜LJ˜Jšœ)˜)J˜šžœ5žœ žœžœ˜MJšœ4˜4Jšœ+˜+J˜Jšœ!™!šžœž˜šœžœžœ˜%Jšœ?˜?šžœ˜Jšžœžœžœ˜6šœ(˜(šžœžœ˜J˜šŸœž œ˜Jšœžœžœ&˜=Jšžœžœ(˜Dšžœžœ)˜EJ˜——Jšœ žœ0˜;Jšœžœ žœ˜+Jšœ<˜J˜—šœžœ˜-šžœžœ˜4J˜——šœžœ˜-šžœ žœžœ˜˜>J˜šžœžœ˜šžœžœžœžœžœžœžœ˜GJšœA˜AJšœU˜UJšœJ˜JJšœ”˜”—J˜š žœ žœžœ žœžœžœ˜PJšœL˜LJšœ`˜`JšœU˜UJšœ―˜―—J˜Jšœr˜rJ™Jšœ™šžœ žœ˜Jšœ#žœžœ*˜išœ)žœž˜GJšœ]žœ˜d—J˜Jšœ.˜.Jšœ8˜8J˜————Jšœ#žœ˜=Jšœ-˜-šžœ/žœ žœžœ˜HJšœ0˜0Jšžœ˜J˜—Jšœ5˜5Jšœ˜J˜—š Ÿ œžœž œ žœžœ˜MJšœ™J˜šœ"˜"JšœžœU˜p—J˜Jšœ#žœ˜=Jšœ-˜-Jšœ.˜.Jšœ˜JšœG˜GJšœ+˜+Jšœ˜JšœP˜PJ˜—šŸ œžœž œ žœ ˜5Jšœ™šœ"˜"Jšœ$žœžœB˜v—J˜Jšœ3˜3Jšœ.˜.Jšœ˜Jšœ8˜8J˜—š Ÿœžœž œ žœžœ˜HJšœ˜Jšœ$˜$J˜—š Ÿœžœž œ žœ5žœ!˜Jšœ™JšœE™EJšœžœ˜.Jš œ žœžœžœžœ˜MJšœAžœžœ˜KJ˜J™Jšœ9™9JšœJ˜JJšœK˜K—J™š Ÿœžœž œ žœ+žœ˜oJšœ™J˜Jšžœžœžœžœ˜;šžœ˜Jšœžœ7˜Ašœ˜Jšœ\˜\—Jšœ%˜%Jšœ#˜#JšœF˜F——J˜šŸ œžœž œ žœ:˜cJšœ%™%J˜šœ(˜(Jšœ*˜*—J˜Jšœ5˜5J˜—šŸ œžœž œ žœV˜}Jšœ™šœ)˜)šžœžœ˜Jšœ˜Jšœ@˜@——J˜Jšœ!˜!Jšœz˜zJšœF˜FJšœ"˜"J˜—š Ÿœžœž œ žœ*žœ[˜·˜Jšžœh˜o—Jšœ™J˜Jšœ#žœ˜=Jšœ#žœ˜?Jšœ%˜%Jšœ˜Jšœ˜Jšœ˜J˜Jšœ4™4Jšžœžœ0˜˜gJšžœžœžœžœ˜?—J˜Jšœ™Jšœc˜cJ˜šœ#˜#Jšœ!˜!Jšœ4˜4Jšœ8˜8—Jšœ+˜+—J˜—šœ(˜(šžœžœž˜3šžœ ž˜&Jšœ[˜[JšœPžœ žœ˜m—Jšžœ˜ —J˜—Jšœ ˜ J™Jšœ"™"Jšœ9˜9J˜Jšœ&˜&J˜Jšœ™šžœžœ˜Jšžœ-žœžœžœ˜NJšœ.˜.Jšœ0˜0JšœF˜FJšœI˜I—J˜Jšœ4˜4J˜Jšœ ˜ Jšœ!˜!Jšœ#˜#Jšžœ˜—Jšœ5˜5Jšœ˜J˜—šŸœžœž œ žœ}˜©Jšžœh˜oJšœ#™#J˜šœ&˜&Jšžœžœ*˜FJ˜—šŸœž œH˜bJšœ.™.J˜Jšœ9žœ˜DJšœ˜Jšœ˜J˜Jšœ3˜3šžœžœžœ˜?š žœžœ žœžœžœžœž˜HJšžœžœ˜ ——šžœžœ'žœ(žœ˜^š žœžœ žœžœ žœžœž˜UJšžœžœ˜!——šžœžœ'žœ˜Lšžœžœ$žœ&ž˜VJšžœžœ˜!——šžœžœ(žœ˜Nšžœžœ#žœ%ž˜TJšžœžœ˜"———J˜Jšœ™Jšœ™Jšœ#žœ˜=Jšœ#žœ˜BJšœ3˜3Jšœ-˜-Jšœ˜Jšœ˜Jšœ˜J˜šžœž œžœžœ˜MJšœ2˜2Jšœžœ ˜(JšœB˜BJšžœžœžœžœ˜>J˜JšœH˜Hšœ/˜/Jšœ(˜(—šœ1˜1Jšœ"˜"Jšœ-˜-—Jšžœ˜—J˜Jšœ™Jšœ2˜2J™Jšœ™šžœ ž œžœžœ˜Ošœ+˜+šžœ žœžœž˜*Jšœ)˜)šžœ3žœ˜;Jšœ˜Jšœ&˜&šœ1˜1Jšœ)˜)—JšœPžœ žœ˜m—Jšžœ˜ —J˜—Jš œ žœžœžœžœ˜CJšœ4˜4Jšœ)˜)Jšœ*˜*Jšœ7˜7J˜Jšœ(™(Jšœ6˜6Jšžœ˜—J™Jšœ5˜5Jšžœ˜—˜šŸ œžœž œ žœ ˜4Jšœ™šœ"˜"šœ,˜,šœ)˜)šœ%˜%Jšžœžœžœ˜$J˜—Jšœ žœZ˜nJšœžœ@˜Nš žœ žœžœžœž˜8Jšžœžœ˜!—J˜—Jšœ6˜6—Jšœ9˜9—Jšœ/˜/—J˜šŸœžœž œ žœ ˜2Jšœ)™)J˜Jšœ>˜>Jšœ/˜/—J˜šŸ œžœž œ žœ ˜JJšœ$™$J˜šœ"˜"šœ#˜#šžœžœ˜"Jšœ3˜3Jšœ3˜3š žœ žœžœ žœžœž˜;Jšœ™Jšžœžœ˜ —šžœžœ˜šžœž˜Jšœ0™0Jšžœžœ˜ —JšœT˜T——J˜—Jšœ=˜=J˜—Jšœ1˜1Jšœ.˜.šžœ/ž˜5Jšœ-™-Jšžœžœ˜!——J˜šŸ œž œ žœ8˜[J˜Jšœ%™%Jšœ#žœ˜=Jšœžœ˜.Jšžœ žœžœžœ˜Gšœ1˜1Jšœ1˜1—Jšœ4˜4Jšœ(˜(—J˜š Ÿœž œ žœhžœžœ˜°J˜Jšœ™Jšœ#žœ˜=Jšœ-˜-Jšœ3˜3JšœI˜IJšœ)˜)Jšœ˜J˜Jšœžœžœ˜šžœžœ ž˜)Jšžœžœžœ ž˜8Jšžœ˜Jšžœ˜—J™Jšœ™Jšœžœ˜šžœ žœ ž˜Jšžœžœžœ ž˜Jšžœžœžœ#˜FJšžœ˜ ———J˜šŸœžœž œ žœ%˜SJ˜Jšœ#žœ˜=Jšœ-˜-šžœ/žœ žœžœ˜HJšœ ˜ Jšœ˜Jšœ˜JšœA˜AJšœ9žœ˜DJšœM˜MJ˜Jšœ#˜#Jšœ ˜ Jšœ!˜!J˜šžœžœ˜Jšœ3˜3J˜š žœžœžœ žœžœž˜IJšœ/˜/—J˜š žœžœžœžœžœž˜JJšœ1˜1—J˜šžœžœ˜šžœžœžœžœžœžœžœ˜IJ˜+JšœK˜K—J˜šžœ žœžœ žœžœžœžœ˜UJ˜6JšœV˜V—J˜JšœDžœ˜L——Jšžœ˜—Jšœ˜J˜—šŸœžœž œ žœ ˜>Jšœ™J˜šœ"˜"Jšœžœ˜&Jšœ™—J˜Jšœ/˜/J˜—šŸœžœž œ žœ ˜Jšœ"˜"Jšžœ˜—J˜Jšœ™šžœ ž œžœžœ˜Ošœ(˜(šžœ žœžœž˜*Jšœ)˜)Jšžœ>žœ)˜mšžœ˜ J˜———Jšœ4˜4Jšœ)˜)Jšœ*˜*Jšœ4˜4Jšžœ˜—Jšžœ ˜—J˜š Ÿ œžœž œ žœ(žœ ˜_˜"Jšœ˜Jšœ˜Jšœ3˜3Jšœ5˜5Jšœ9žœ˜DJšœM˜MJ˜šžœžœ˜Jšœ3˜3J˜šžœžœ˜š žœžœžœžœžœž˜EJšœJ˜J—J˜š žœžœžœ žœžœž˜MJšœU˜U—J˜JšœGžœ˜Q———J˜Jšœ#žœ˜=Jšœ-˜-Jšœ/˜/J˜—šŸ œžœž œ žœ ˜7J˜Jšœ>˜>Jšœ#žœ˜=Jšœ$˜$Jšœ5˜5—Jšœ˜———…—oͺ‘5