DIRECTORY Basics, CD, CDBasics, CDProperties, CDRects, CDRoutingObjects, CDSimpleRules, CMosB, Convert, Core, CoreClasses, CoreGeometry, CoreOps, CoreProperties, CoreRoute, CoreXform, DataPath, RefTab, IO, PW, PWCore, Rope, Sisyph, SymTab, TerminalIO; DataPathLayout: CEDAR PROGRAM IMPORTS Basics, CD, CDBasics, CDProperties, CDRects, CDRoutingObjects, CDSimpleRules, CMosB, Convert, CoreClasses, CoreGeometry, CoreOps, CoreProperties, CoreRoute, CoreXform, DataPath, RefTab, IO, PW, PWCore, Rope, Sisyph, SymTab, TerminalIO EXPORTS DataPath SHARES CDRects = BEGIN OPEN DP: DataPath; Signal: SIGNAL[msg: DP.ROPE _ NIL] = CODE; DrawingError: SIGNAL = CODE; schDeco: PUBLIC CoreGeometry.Decoration _ Sisyph.mode.decoration; layDeco: PUBLIC CoreGeometry.Decoration _ PWCore.extractMode.decoration; layRules: ATOM _ $cmosB; dpKeyTab: SymTab.Ref _ SymTab.Create[]; sectionRtEdge: NAT _ LAST[NAT]; Layout: PWCore.LayoutProc ~ { data: CoreClasses.RecordCellType _ NARROW[cellType.data]; spec: DP.DPSpec _ NewCellTypeSpec[cellType]; interleave: BOOL _ CoreProperties.GetCellTypeProp[cellType, $DataPathInterleave]#NIL; refPolyBits: REF INT _ NARROW [CoreProperties.GetCellTypeProp[cellType, $ChanPolyBits]]; schIR: CD.Rect _ [x1: LAST[INT], x2: FIRST[INT], y1: LAST[INT], y2: FIRST[INT]]; xIntervals: DP.Intervals _ NIL; yIntervals: DP.Intervals _ NIL; yIntervalsCh: DP.Intervals _ NIL; colBuss: NAT _ spec.buses*spec.schBusW; count: NAT _ 0; nofRows: NAT _ 0; nofCols: NAT _ 0; row: NAT _ 0; col: NAT _ 0; dp: DP.Form _ NIL; loc: CD.Position; size: CD.Position; spec.n _ GetSize[data[0].type]; spec.cols _ 0; spec.interleave _ interleave; spec.chPolyBits _ IF refPolyBits#NIL THEN refPolyBits^ ELSE 0; FOR child: NAT IN [0..data.size) DO width: INT _ spec.schDWidth+colBuss; exposedBusses: INT; [loc, size] _ LocSize[data.instances[child]]; exposedBusses _ (width-size.x+slop)/spec.schBusW; -- icons must be correct width xIntervals _ InsertInterval[[loc.x-exposedBusses*spec.schBusW, width], xIntervals]; yIntervals _ InsertInterval[[loc.y, size.y], yIntervals]; ENDLOOP; yIntervalsCh _ FindChIntervals[spec, cellType, yIntervals]; FOR list: DP.Intervals _ yIntervals, list.rest WHILE list#NIL DO nofRows _ nofRows+1; schIR.y1 _ MIN[schIR.y1, list.first.loc]; schIR.y2 _ MAX[schIR.y2, list.first.loc + list.first.size]; IF list.rest#NIL AND list.first.loc + list.first.size > list.rest.first.loc THEN Signal[ IO.PutFR["Rows %g and %g Overlap\n", IO.int[nofRows], IO.int[nofRows+1]]] ENDLOOP; FOR list: DP.Intervals _ yIntervalsCh, list.rest WHILE list#NIL DO nofRows _ nofRows+1; schIR.y1 _ MIN[schIR.y1, list.first.loc]; schIR.y2 _ MAX[schIR.y2, list.first.loc + list.first.size]; IF list.rest#NIL AND list.first.loc + list.first.size > list.rest.first.loc THEN Signal[] ENDLOOP; FOR list: DP.Intervals _ xIntervals, list.rest WHILE list#NIL DO nofCols _ nofCols+1; schIR.x1 _ MIN[schIR.x1, list.first.loc]; schIR.x2 _ MAX[schIR.x2, list.first.loc + list.first.size]; IF list.rest#NIL AND list.first.loc + list.first.size > list.rest.first.loc THEN Signal[] ENDLOOP; dp _ NEW[DP.RowSeqRec[nofRows]]; dp.schIR _ schIR; dp.cell _ cellType; dp.spec _ spec; dp.wpo _ RefTab.Create[]; IF dp.spec.cols#0 AND dp.spec.cols#nofCols THEN Signal[]; dp.spec.cols _ nofCols; FOR row IN [0..dp.size) DO sb: BOOL _ yIntervals=NIL OR yIntervalsCh#NIL AND yIntervalsCh.first.loc Signal[] ENDLOOP; FOR col DECREASING IN [0..dp[row].size) DO IF dp[row][col].schIR.x1 <= loc.x THEN EXIT REPEAT FINISHED => Signal[] ENDLOOP; IF dp[row][col].schInst#NIL THEN Signal[]; dp[row][col].schInst _ data.instances[child]; IF (SchHalfBus[spec, loc.x - dp[row][col].schIR.x1] MOD 2) # 0 THEN Signal[]; dp[row][col].devBOff _ SchHalfBus[spec, loc.x - dp[row][col].schIR.x1]/2; ENDLOOP; ShowDP[dp]; FOR row IN [0..dp.size) DO IF dp[row].ch=NIL THEN FOR col IN [0..dp[row].size) DO IF dp[row][col].schInst=NIL THEN LOOP; dp[row][col].devCells _ GetDeviceCellTypes[dp[row][col].schInst]; dp[row].layY.size _ CDBasics.SizeOfRect[PWCore.InterestRect[dp[row][col].devCells[0]]].y ENDLOOP ENDLOOP; AddExplicitRoutingChannel[dp]; AddImplicitRoutingChannel[dp]; FOR row IN [0..dp.size) DO IF dp[row].ch#NIL THEN DP.BuildChan[dp, row] ENDLOOP; FOR row IN [1..dp.size) DO dp[row].layY.loc _ dp[row-1].layY.loc+dp[row-1].layY.size ENDLOOP; dp.layIR _ [ x1: 0, x2: BitWidth[dp.spec]*dp.spec.cols*dp.spec.n, y1: 0, y2: dp[dp.size-1].layY.loc+dp[dp.size-1].layY.size ]; AddExplicitRoutingSwitchBox[dp]; AddImplicitRoutingSwitchBox[dp]; AddExplicitDecorations[dp]; AddImplicitDecorations[dp]; obj _ dp.obj _ AssembleObject[dp]; TerminalIO.PutF["\nLayout %g\n", IO.rope[CoreOps.GetCellTypeName[dp.cell]]]; TerminalIO.PutF[" %g transistors\n", IO.int[CountTransistors[dp.cell]]]; ShowDP[dp]; TerminalIO.PutF["Layout Size (CMosB.lambda) x: %g y: %g xy: %g\n", IO.int[CD.InterestSize[obj].x/CMosB.lambda], IO.int[CD.InterestSize[obj].y/CMosB.lambda], IO.int[(CD.InterestSize[obj].x/CMosB.lambda)*(CD.InterestSize[obj].y/CMosB.lambda)] ]}; FindChIntervals: PROC[spec: DP.DPSpec, cell: DP.CellType, instY: DP.Intervals] RETURNS[sbIVals: DP.Intervals_NIL] = { data: CoreClasses.RecordCellType _ NARROW[cell.data]; CheckAndAdd: PROC[loc: INT] = { last: INT _ schIR.y1+2; FOR list: DP.Intervals _ instY, list.rest WHILE list#NIL DO IF loc < list.first.loc THEN {sbIVals _ InsertInterval[[last, list.first.loc-last], sbIVals]; RETURN}; IF loc < list.first.loc + list.first.size THEN RETURN; last _ list.first.loc + list.first.size; REPEAT FINISHED => sbIVals _ InsertInterval[[last, schIR.y2-2-last], sbIVals] ENDLOOP}; eachWireInst: EachWireInst = { instIR: CD.Rect _ CDBasics.MapRect[CD.InterestRect[geo.obj], geo.trans]; hor: BOOL _ (instIR.x2-instIR.x1) >= spec.schBusW/2; loc: INT _ (instIR.y1+instIR.y2)/2; IF hor THEN CheckAndAdd[loc]}; schIR: CD.Rect _ CD.InterestRect[CoreGeometry.GetObject[schDeco, cell]]; FOR child: NAT IN [0..data.size) DO pos, size: CD.Position; [pos, size] _ LocSize[data.instances[child]]; CheckAndAdd[pos.y + size.y/2] ENDLOOP; EnumInternalSchematicGeometry[cell, eachWireInst]}; InsertInterval: PROC[intvl: DP.Interval, intvls: DP.Intervals] RETURNS[result: DP.Intervals] = { result _ CONS[intvl, intvls]; FOR intvls _ result, intvls.rest WHILE intvls#NIL DO TwoIntervals: TYPE = RECORD[i0, i1: DP.Interval]; IF intvls.rest=NIL OR intvls.first.loc < intvls.rest.first.loc THEN RETURN; IF intvls.first = intvls.rest.first THEN {intvls.rest _ intvls.rest.rest; RETURN}; IF intvls.first.loc = intvls.rest.first.loc THEN IF intvls.first.size < intvls.rest.first.size THEN RETURN ELSE [intvls.first, intvls.rest.first] _ TwoIntervals[intvls.rest.first, intvls.first]; [intvls.first, intvls.rest.first] _ TwoIntervals[intvls.rest.first, intvls.first]; ENDLOOP}; EachWireInst: TYPE = PROC[w: DP.Wire, geo: CoreGeometry.Instance]; GetGlobalNames: PROC[dp: DP.Form] RETURNS[globals: LIST OF DP.ROPE] = {globals _ LIST["Gnd", "Vdd", "Vbb"]}; EnumInternalSchematicGeometry: PROC[cell: DP.CellType, eachWireInst: EachWireInst] = { data: CoreClasses.RecordCellType _ NARROW[cell.data]; EnumSchematicGeometry: CoreOps.EachWireProc ~ { geometry: CoreGeometry.Instances _ CoreGeometry.GetGeometry[schDeco, wire]; IF ~RefTab.Store[visitOnceTab, wire, wire] THEN RETURN[FALSE, FALSE]; -- only once IF geometry=NIL THEN RETURN[subWires: TRUE]; FOR geometry _ geometry, geometry.rest WHILE geometry#NIL DO eachWireInst[wire, geometry.first] ENDLOOP; RETURN[subWires: TRUE]}; visitOnceTab: RefTab.Ref _ RefTab.Create[]; []_CoreOps.VisitWire[data.internal, EnumSchematicGeometry]; RefTab.Erase[visitOnceTab]; visitOnceTab _ NIL}; AddExplicitRoutingChannel: PROC[dp: DP.Form] = { eachWireInst: EachWireInst = { instIR: CD.Rect _ CDBasics.MapRect[ CD.InterestRect[geo.obj], geo.trans]; lc: DP.LayoutCoord _ GetLayoutCoord[dp, w, instIR, TRUE]; IF lc.hor OR lc.inBody THEN FOR row: NAT IN [lc.rowBot..lc.rowTop] DO IF dp[row].ch#NIL THEN DP.AddChanNode[dp, row, w, lc]; ENDLOOP}; EnumInternalSchematicGeometry[dp.cell, eachWireInst]}; AddImplicitRoutingChannel: PROC[dp: DP.Form] = { FOR row: INT DECREASING IN [0..dp.size) DO IF dp[row].ch#NIL THEN DP.AddPowerPassBuses[dp, row] ENDLOOP}; AddExplicitRoutingSwitchBox: PROC[dp: DP.Form] = { eachWireInst: EachWireInst = { instIR: CD.Rect _ CDBasics.MapRect[ CD.InterestRect[geo.obj], geo.trans]; bigLC: DP.LayoutCoord _ GetLayoutCoord[dp, w, instIR, FALSE]; IF geo.obj.class#CDRects.bareRectClass THEN Signal[]; IF bigLC.inBody THEN FOR row: NAT IN [bigLC.rowBot..bigLC.rowTop] DO IF dp[row].ch#NIL THEN LOOP; FOR col: NAT IN [bigLC.colLt..bigLC.colRt] DO lc: DP.LayoutCoord _ TrimLayoutCoord[dp, bigLC, row, col]; IF lc.hor THEN { IF lc.busLt IN [1..dp.spec.buses*2) THEN AddPObj[dp[row][col].wpo, w, ContPObj[dp.spec, lc.busLt, lc.yTop, lc.horLayTop]]; IF lc.busRt IN [1..dp.spec.buses*2) THEN AddPObj[dp[row][col].wpo, w, ContPObj[dp.spec, lc.busRt, lc.yTop, lc.horLayTop]]; AddPObj[dp[row][col].wpo, w, HorPObj[dp.spec, lc.yTop, lc.busLt, lc.busRt, lc.horSize, lc.horLayTop]]}; IF ~lc.hor THEN { IF lc.yBot IN (0..dp[row].layY.size) THEN AddPObj[dp[row][col].wpo, w, ContPObj[dp.spec, lc.busLt, lc.yBot, lc.horLayBot]]; IF lc.yTop IN (0..dp[row].layY.size) THEN AddPObj[dp[row][col].wpo, w, ContPObj[dp.spec, lc.busLt, lc.yTop, lc.horLayTop]]; AddPObj[dp[row][col].wpo, w, VerPObj[dp.spec, lc.yBot, lc.yTop, lc.busLt, dp.spec.metW]]}; ENDLOOP; ENDLOOP}; EnumInternalSchematicGeometry[dp.cell, eachWireInst]}; AddImplicitRoutingSwitchBox: PROC[dp: DP.Form] = { AddImplicitRoutingSwitchBoxSides[dp]; AddImplicitRoutingSwitchBoxEnds[dp]}; -- only needed for missing instances AddImplicitRoutingSwitchBoxSides: PROC[dp: DP.Form] = { FOR globals: LIST OF DP.ROPE _ GetGlobalNames[dp], globals.rest WHILE globals#NIL DO FOR row: NAT IN [0..dp.size) DO refCol: NAT; actualWire: DP.Wire; cell: DP.CellType; lss: LSs; IF dp[row].ch#NIL THEN LOOP; FOR refCol _ 0, refCol+1 WHILE refCol ERROR ENDLOOP; actualWire _ CoreOps.FindWire[dp[row][refCol].schInst.actual, globals.first]; cell _ dp[row][refCol].devCells[0]; lss _ GetGeometryLocSizes [cell, CoreOps.FindWire[cell.public, globals.first], right, CMosB.met2]; FOR lss _ lss, lss.rest WHILE lss#NIL DO FOR col: NAT IN [0..dp[row].size) DO cWidth: INT _ IF dp[row][col].schInst=NIL THEN sectionRtEdge ELSE dp.spec.buses*2; AddPObj[ dp[row][col].wpo, actualWire, HorPObj[dp.spec, lss.first.loc+lss.first.size/2,0,cWidth,lss.first.size,CMosB.met2] ]; ENDLOOP; ENDLOOP; ENDLOOP; ENDLOOP}; AddImplicitRoutingSwitchBoxEnds: PROC[dp: DP.Form] = { gnd: DP.Wire = CoreOps.FindWire[dp.cell.public, "Gnd"]; vdd: DP.Wire = CoreOps.FindWire[dp.cell.public, "Vdd"]; IF dp.spec.gndBus<=0 THEN RETURN; IF dp.spec.vddBus<=0 THEN ERROR; FOR row: INT DECREASING IN [0..dp.size) DO ytop: INT _ dp[row].layY.size; IF dp[row].ch#NIL THEN LOOP; FOR col: INT DECREASING IN [0..dp[row].size) DO IF dp[row][col].schInst#NIL THEN LOOP; AddPObj[dp[row][col].wpo, gnd, VerPObj[dp.spec, 0, ytop, (dp.spec.gndBus+1)*2-1, dp.spec.pwrW]]; AddPObj[dp[row][col].wpo, vdd, VerPObj[dp.spec, 0, ytop, (dp.spec.vddBus+1)*2-1, dp.spec.pwrW]]; ENDLOOP ENDLOOP}; AddExplicitDecorations: PROC[dp: DP.Form] = { tagVer: DP.Object _ CDRects.CreateRect[ [x: dp.spec.metW, y: dp.spec.pinSize], CMosB.met]; tagHor: DP.Object _ CDRects.CreateRect[ [x: dp.spec.pinSize, y: dp.spec.met2W], CMosB.met2]; eachWireInst: EachWireInst = { instIR: CD.Rect _ CDBasics.MapRect[ CD.InterestRect[geo.obj], geo.trans]; bigLC: DP.LayoutCoord _ GetLayoutCoord[dp, w, instIR, FALSE]; IF bigLC.sides#CoreGeometry.noSide THEN { tag: DP.Object _ IF bigLC.hor THEN tagHor ELSE tagVer; FOR side: DP.Side IN DP.Side DO loc: CD.Position; IF NOT bigLC.sides[side] THEN LOOP; IF side=top OR side=bottom THEN FOR bit: INT IN [0..dp.spec.n) DO kid: DP.Wire _ IF w.size=0 THEN w ELSE w[bit]; loc.y _ SELECT side FROM bottom => 0, top => dp.layIR.y2 - CD.InterestSize[tag].y ENDCASE=>ERROR; loc.x _ BitPosX[dp.spec, bigLC.colLt, bit] + dp.spec.leftTail + (bigLC.busLt-1)*dp.spec.layBusW/2 - dp.spec.metW/2; AddPObj[dp.wpo, kid, [tag, loc]]; AddPin[ kid, [tag, loc]]; ENDLOOP; IF side=left OR side=right THEN { range: INT _ IF w.size=0 THEN 1 ELSE w.size; FOR bit: INT IN [0..range) DO kid: DP.Wire _ IF w.size=0 THEN w ELSE w[bit]; layy: INT _ IF dp[bigLC.rowBot].ch#NIL THEN DP.GetChanY[dp[bigLC.rowBot].ch, kid].loc ELSE bigLC.yBot; IF dp[bigLC.rowBot].ch=NIL AND w.size#0 THEN ERROR; loc.x _ SELECT side FROM left => 0, right => dp.layIR.x2- CD.InterestSize[tag].x, ENDCASE =>ERROR; loc.y _ dp[bigLC.rowBot].layY.loc + layy - bigLC.horSize/2; IF bigLC.horLayBot#CMosB.met2 THEN ERROR; AddPObj[dp.wpo, kid, [tag, loc]]; AddPin[ kid, [tag, loc]]; ENDLOOP}; ENDLOOP } }; EnumInternalSchematicGeometry[dp.cell, eachWireInst]}; AddImplicitDecorations: PROC[dp: DP.Form] = { AddImplicitSideDecorations[dp]; AddImplicitEndDecorations[dp]}; AddImplicitSideDecorations: PROC[dp: DP.Form] = { loc: CD.Position; tag: DP.Object; FOR row: NAT IN [0..dp.size) DO FOR globals: LIST OF DP.ROPE _ GetGlobalNames[dp], globals.rest WHILE globals#NIL DO cell: DP.CellType; wire: DP.Wire; actWire: DP.Wire _ CoreOps.FindWire[dp.cell.public, globals.first]; lssLt, lssRt: LSs; IF dp[row].ch#NIL THEN { lss: LSRec; IF NOT RefTab.Fetch[dp[row].ch, actWire].found THEN LOOP; lss _ [loc: DP.GetChanY[dp[row].ch, actWire].loc - dp.spec.met2W/2, size: dp.spec.met2W]; lssLt _ CONS[lss, NIL]; lssRt _ CONS[lss, NIL]} ELSE { FOR refCol: INT _ 0, refCol+1 WHILE refCol ERROR ENDLOOP; FOR refCol: INT _ dp[row].size-1, refCol-1 WHILE refCol>=0 DO IF dp[row][refCol].schInst=NIL THEN LOOP; cell _ dp[row][refCol].devCells[0]; wire _ CoreOps.FindWire[cell.public, globals.first]; lssRt _ GetGeometryLocSizes[dp[row][refCol].devCells[0], wire, right, CMosB.met2]; EXIT REPEAT FINISHED => ERROR ENDLOOP}; FOR lss: LSs _ lssLt, lss.rest WHILE lss#NIL DO tag _ CDRects.CreateRect[ [x: dp.spec.pinSize, y: lss.first.size], CMosB.met2]; loc _ [0, dp[row].layY.loc + lss.first.loc]; AddPObj[dp.wpo, actWire, [tag, loc]]; AddPin[ actWire, [tag, loc]] ENDLOOP; FOR lss: LSs _ lssRt, lss.rest WHILE lss#NIL DO tag _ CDRects.CreateRect[ [x: dp.spec.pinSize, y: lss.first.size], CMosB.met2]; loc _ [dp.spec.cols*dp.spec.n*BitWidth[dp.spec]- CD.InterestSize[tag].x, dp[row].layY.loc + lss.first.loc]; AddPObj[dp.wpo, actWire, [tag, loc]]; AddPin[ actWire, [tag, loc]] ENDLOOP; ENDLOOP; ENDLOOP}; AddImplicitEndDecorations: PROC[dp: DP.Form] = { gnd: DP.Wire = CoreOps.FindWire[dp.cell.public, "Gnd"]; vdd: DP.Wire = CoreOps.FindWire[dp.cell.public, "Vdd"]; tag: CD.Object _ CDRects.CreateRect[ [x: dp.spec.pwrW, y: dp.spec.pinSize], CMosB.met]; row: INT _ 0; IF dp.spec.gndBus<=0 THEN RETURN; IF dp.spec.vddBus<=0 THEN ERROR; DO topPos: CD.Position _ [0, dp[row].layY.loc + dp[row].layY.size - CD.InterestSize[tag].y]; botPos: CD.Position _ [0, 0]; FOR col: INT IN [0..dp[row].size) DO FOR bit: INT IN [0..dp.spec.n) DO gndx: INT _ BitWidth[dp.spec]*(col*dp.spec.n+bit) + dp.spec.gndBus*dp.spec.layBusW + dp.spec.leftTail - CD.InterestSize[tag].x/2; vddx: INT _ BitWidth[dp.spec]*(col*dp.spec.n+bit) + dp.spec.vddBus*dp.spec.layBusW + dp.spec.leftTail - CD.InterestSize[tag].x/2; IF row+1=dp.size THEN { topPos.x _ gndx; AddPObj[dp.wpo, gnd, [tag, topPos]]; AddPin[gnd, [tag, topPos]]; topPos.x _ vddx; AddPObj[dp.wpo, vdd, [tag, topPos]]; AddPin[vdd, [tag, topPos]]}; IF row=0 THEN { botPos.x _ gndx; AddPObj[dp.wpo, gnd, [tag, botPos]]; AddPin[gnd, [tag, botPos]]; botPos.x _ vddx; AddPObj[dp.wpo, vdd, [tag, botPos]]; AddPin[vdd, [tag, botPos]]} ENDLOOP ENDLOOP; IF row = dp.size-1 THEN EXIT ELSE row _ dp.size-1 ENDLOOP}; LSs: TYPE = LIST OF LSRec; LSRec: TYPE = RECORD[loc, size: INT]; slop: INT _ CMosB.lambda/2; BitWidth: PUBLIC PROC[spec: DP.DPSpec] RETURNS[bitWidth: INT] = {RETURN[spec.layBusW*spec.buses + spec.layDWidth]}; BitPosX: PUBLIC PROC[spec: DP.DPSpec, col, bit: NAT] RETURNS[pos: INT] = { xform: CoreXform.Xform _ CoreXform.GenXform[(IF spec.interleave THEN LIST[[spec.cols, 1], [spec.n, 0]] ELSE LIST[[spec.cols, 0], [spec.n, 1]] )]; logical: INT _ col*spec.n + bit; RETURN[BitWidth[spec] * CoreXform.XformIndex[xform, lr, logical].i ]}; SchBodyIR: PROC[dp: DP.Form] RETURNS[schIR: CD.Rect] = { schIR _ [ x1: dp[0][0].schIR.x1, y1: dp[0][0].schIR.y1, x2: dp[dp.size-1][dp[0].size-1].schIR.x2, y2: dp[dp.size-1][dp[0].size-1].schIR.y2]}; SchRowIR: PROC[dp: DP.Form, row: INT] RETURNS[schIR: CD.Rect] = { schIR _ [ x1: dp[row][0].schIR.x1, y1: dp[row][0].schIR.y1, x2: dp[row][dp[0].size-1].schIR.x2, y2: dp[row][dp[0].size-1].schIR.y2]}; GetLayoutCoordSides: PROC[dp: DP.Form, schIR: CD.Rect] RETURNS[sides: DP.Sides] = { externalIR: CD.Rect _ CD.InterestRect[CoreGeometry.GetObject[schDeco, dp.cell]]; sides[left] _ schIR.x1 < externalIR.x1 + slop; sides[bottom] _ schIR.y1 < externalIR.y1 + slop; sides[right] _ schIR.x2 > externalIR.x2 - slop; sides[top] _ schIR.y2 > externalIR.y2 - slop}; GetLayoutHor: PROC[schIR: CD.Rect] RETURNS[hor: BOOL] = { comp: Basics.Comparison _ Basics.CompareInt[schIR.x2-schIR.x1, schIR.y2-schIR.y1]; RETURN[SELECT comp FROM less => FALSE, greater => TRUE, ENDCASE => TRUE]}; -- little wire icon pins GetLayoutCoord: PROC[dp: DP.Form, wire: DP.Wire, schIR: CD.Rect, initialLayYSize: BOOL] RETURNS[lc: DP.LayoutCoord] = { OPEN CDB: CDBasics; lc.inBody _ CDB.Intersect[schIR, CDB.Extend[SchBodyIR[dp], -slop-1]]; lc.sides _ GetLayoutCoordSides[dp, schIR]; lc.hor _ GetLayoutHor[schIR]; FOR row: NAT IN [0..dp.size) DO notOutSideRow: BOOL _ CDB.Inside[schIR, CDB.Extend[SchRowIR[dp, row], -slop] ]; IF notOutSideRow AND dp[row].ch#NIL THEN {lc.rowBot _ lc.rowTop _ row; lc.yBot _ lc.yTop _ dp.spec.initialYSize/2; RETURN[lc]}; FOR col: NAT IN [0..dp[row].size) DO ENABLE DrawingError => { TerminalIO.PutF["Drawing Error in row %g col %g\n", IO.int[row], IO.int[col]]; TerminalIO.PutF[" x1: %g y1: %g x2: %g y2: %g \n", IO.int[schIR.x1], IO.int[schIR.y1], IO.int[schIR.x2], IO.int[schIR.y2]]; REJECT}; GetY: PROC[schy: INT] RETURNS[layy, size: INT, layer: CD.Layer] = { layer _ CMosB.met2; IF initialLayYSize OR dp[row].ch#NIL THEN RETURN[dp.spec.initialYSize/2, dp.spec.met2W, CMosB.met2]; FOR sideIndex: INT IN [0..1] DO side: DP.Side _ IF (sideIndex=0)=firstSideRight THEN right ELSE left; incr: INT _ IF side=right THEN -1 ELSE +1; FOR cc: INT _ col, cc+incr WHILE cc IN [0..dp.spec.cols) DO IF dp[row][cc].schInst=NIL THEN LOOP; THROUGH [0..1] DO -- check both pol and met2 lss: LSs _ IconToLayoutGeoLocSizes[dp[row][cc], wire, schy, side, layer]; IF lss#NIL THEN RETURN[lss.first.loc+lss.first.size/2, lss.first.size, layer]; layer _ IF layer=CMosB.pol THEN CMosB.met2 ELSE CMosB.pol; ENDLOOP ENDLOOP ENDLOOP; ERROR}; firstSideRight: BOOL _ FALSE; slopGap: INT _ IF row>0 THEN dp[row].schIR.y1 - dp[row-1].schIR.y2 + slop ELSE slop; leftEdge: INT _ IF col=0 THEN dp[row][col].schIR.x1 ELSE dp[row][col-1].schIR.x2; SELECT TRUE FROM CDB.Intersect[schIR, CDB.Extend[dp[row][col].schIR, -1]] => { }; -- doit lc.inBody => LOOP; lc.sides[bottom] AND row = 0 => { }; -- doit lc.sides[left] AND col = 0 => { }; -- doit lc.sides[top] AND row = dp.size-1 => { }; -- doit lc.sides[right] AND col = dp[0].size-1 => { }; -- doit ENDCASE => LOOP; IF lc.hor AND schIR.x1 <= dp[row][col].schIR.x1 OR lc.hor AND schIR.x2 >= dp[row][col].schIR.x2 THEN firstSideRight _ TRUE; IF schIR.x1 IN [leftEdge-slop..dp[row][col].schIR.x1+slop) THEN { lc.colLt _ col; lc.busLt _ 0}; IF schIR.x1 IN [dp[row][col].schIR.x1+slop..dp[row][col].schIR.x2-slop) THEN { lc.colLt _ col; lc.busLt _ SchHalfBus[dp.spec, schIR.x1-dp[row][col].schIR.x1]}; IF schIR.x2 IN (dp[row][col].schIR.x1+slop..dp[row][col].schIR.x2-slop) THEN { lc.colRt _ col; lc.busRt _ SchHalfBus[dp.spec, schIR.x2-dp[row][col].schIR.x1]}; IF schIR.x2 >= dp[row][col].schIR.x2-slop THEN { lc.colRt _ col; lc.busRt _ sectionRtEdge}; IF schIR.y1 IN [dp[row].schIR.y1-slopGap..dp[row].schIR.y1+slop] THEN { lc.rowBot _ row; lc.yBot _ 0}; IF schIR.y1 IN (dp[row].schIR.y1+slop..dp[row].schIR.y2-slop) THEN { lc.rowBot _ row; [lc.yBot, lc.horSize, lc.horLayBot] _ GetY[schIR.y1-dp[row].schIR.y1]}; IF schIR.y2 IN (dp[row].schIR.y1+slop..dp[row].schIR.y2-slop) THEN { lc.rowTop _ row; [lc.yTop, lc.horSize, lc.horLayTop] _ GetY[schIR.y2-dp[row].schIR.y1]}; IF schIR.y2 >= dp[row].schIR.y2-slop THEN { lc.rowTop _ row; lc.yTop _ IF initialLayYSize THEN dp.spec.initialYSize ELSE dp[row].layY.size}; ENDLOOP; ENDLOOP}; TrimLayoutCoord: PROC[dp: DP.Form, bigLC: DP.LayoutCoord, row, col: NAT] RETURNS[lc: DP.LayoutCoord] = { lc _ bigLC; IF col > bigLC.colLt THEN lc.busLt _ 0; IF col < bigLC.colRt THEN lc.busRt _ sectionRtEdge ; IF row > bigLC.rowBot THEN lc.yBot _ 0; IF row < bigLC.rowTop THEN lc.yTop _ dp[row].layY.size; lc.rowTop _ lc.rowBot _ row; lc.colLt _ lc.colRt _ col }; IconToLayoutGeoLocSizes: PROC [sec: DP.Section, actual: DP.Wire, schLoc: INT, side: DP.Side, layer: CD.Layer] RETURNS[lss: LSs] = { VisitBaseSeqCellBinding: PUBLIC PROC [base, seq: DP.Wire] = { IF seq=iconPub THEN {bitCellPub _ base; RETURN}; FOR i: NAT IN [0 .. base.size) WHILE bitCellPub=NIL DO VisitBaseSeqCellBinding[base[i], seq[i]] ENDLOOP}; iconPub: DP.Wire _ GetSchematicPublic[sec.schInst, actual, side, schLoc]; bitCellPub: DP.Wire; bitCell: DP.CellType _ sec.devCells[0]; IF iconPub=NIL THEN Signal[]; VisitBaseSeqCellBinding[bitCell.public, sec.schInst.type.public]; IF bitCellPub=NIL THEN Signal[]; RETURN [GetGeometryLocSizes[bitCell, bitCellPub, side, layer]]}; GetSchematicPublic: PROC [cellInst: DP.CellInstance, actual: DP.Wire, cSide: DP.Side, schY: INT] RETURNS[schPub: DP.Wire _ NIL] = { eachPair: CoreOps.EachWirePairProc ~ { lss: LSs; IF (actual # actualWire) THEN RETURN; lss _ GetGeometryLocSizes[cellInst.type, publicWire, cSide]; FOR lss _ lss, lss.rest WHILE lss#NIL DO IF schY-lss.first.loc IN [0..lss.first.size] THEN EXIT; REPEAT FINISHED=>RETURN[subWires: FALSE]; ENDLOOP; schPub _ publicWire; RETURN[quit: TRUE]}; []_CoreOps.VisitBinding[cellInst.actual, cellInst.type.public, eachPair]}; GetGeometryLocSizes: PROC [cell: DP.CellType, wire: DP.Wire, cSide: DP.Side, lay: CD.Layer _ CD.commentLayer] RETURNS[lss: LSs _ NIL] = { eachPin: CoreGeometry.EachPinProc = { IF (layer # lay) OR (side # cSide) THEN RETURN; lss _ CONS[LSRec[min, max-min], lss]}; decoration: CoreGeometry.Decoration _ IF lay=CD.commentLayer THEN schDeco ELSE layDeco; IF wire=NIL THEN RETURN[NIL]; []_CoreGeometry.EnumerateSides[decoration, cell, wire, eachPin]}; LocSize: PROC[inst: DP.CellInstance] RETURNS[loc, size: CD.Position] = { obj: CD.Object _ CoreGeometry.GetObject[schDeco, inst.type]; trans: CoreGeometry.Transformation _ CoreGeometry.GetTrans[schDeco, inst]; size _ CD.InterestSize[obj]; loc _ CDBasics.BaseOfRect[CDBasics.MapRect[CD.InterestRect[obj], trans]]; IF trans.orient # original THEN { Signal[IO.PutFR["Schematic object (%g) has been rotated or flipped\n", IO.rope[CoreOps.GetCellTypeName[inst.type] ] ] ] }}; SchHalfBus: PUBLIC PROC[spec: DP.DPSpec, pos: INT] RETURNS[bus: INT] = { RETURN[pos/(spec.schBusW/2)]}; AddPin: PROC [public: DP.Wire, po: DP.PObj] = { pin: CoreGeometry.Instance _ [po.object, [po.position]]; CoreGeometry.AddPins[layDeco, public, LIST[pin]]}; ContPObj: PROC[spec: DP.DPSpec, bus, layY: INT, layer: CD.Layer] RETURNS[po: DP.PObj] = { po.object _ CDSimpleRules.Contact[layRules, CMosB.met, layer]; po.position.x _ spec.leftTail + (bus-1)*spec.layBusW/2 - CD.InterestSize[po.object].x/2; po.position.y _ layY - CD.InterestSize[po.object].x/2}; HorPObj: PROC[spec: DP.DPSpec, layY, lBus, rBus, size: INT, layer: CD.Layer] RETURNS[po: DP.PObj] = { fullW: INT _ BitWidth[spec]; ltEdge: BOOL _ lBus = 0; rtEdge: BOOL _ rBus = sectionRtEdge; x1: INT _ IF ltEdge THEN 0 ELSE spec.leftTail + (lBus-1)*(spec.layBusW/2); x2: INT _ IF rtEdge THEN fullW ELSE spec.leftTail + (rBus-1)*(spec.layBusW/2); IF x1 >= x2 THEN Signal[]; po.object _ CDRects.CreateRect[ [x: x2-x1, y: size], layer]; po.position _ [x1, layY - size/2]}; VerPObj: PROC[spec: DP.DPSpec, layYbot, layYtop, bus: INT, size: INT] RETURNS[po: DP.PObj] = { IF layYbot >= layYtop THEN Signal[]; po.object _ CDRects.CreateRect[ [x: size, y: layYtop-layYbot], CMosB.met]; po.position.x _ spec.leftTail + (bus-1)*spec.layBusW/2 - size/2; po.position.y _ layYbot}; AddPObj: PROC[wpo: RefTab.Ref, wire: DP.Wire, po: DP.PObj] = { pos: DP.PObjs _ NARROW[RefTab.Fetch[wpo, wire].val]; pos _ CONS[po, pos]; [] _ RefTab.Store[wpo, wire, pos]}; AssembleObject: PROC[dp: DP.Form] RETURNS[cell: DP.Object] = { IncludePins: RefTab.EachPairAction = { pos: DP.PObjs _ NARROW[val]; name: DP.ROPE _ CoreRoute.LabelInternal[data.internal, NARROW[key]]; FOR pos _ pos, pos.rest WHILE pos#NIL DO Include[pos.first.object, pos.first.position]; CDProperties.PutProp[insts.first, $SignalName, name] ENDLOOP}; Include: PROC[obj: CD.Object, loc: CD.Position] = { IF obj=NIL THEN RETURN; loc _ CDBasics.SubPoints[loc, CD.InterestBase[obj]]; insts _ CONS[ NEW[CD.InstanceRep _ [obj, [loc]]], insts]}; data: CoreClasses.RecordCellType _ NARROW[dp.cell.data]; name: DP.ROPE _ CoreOps.GetCellTypeName[dp.cell]; insts: CD.InstanceList _ NIL; FOR row: NAT IN [0..dp.size) DO IF dp[row].ch#NIL THEN { Include[dp[row].obj, [0, dp[row].layY.loc]]; LOOP}; FOR col: NAT IN [0..dp[row].size) DO routing: CD.Object _ CreateRoutingObject[dp, row, col]; FOR bit: INT IN [0..dp.spec.n) DO refPos: CD.Position _ [BitPosX[dp.spec, col, bit] + 0, dp[row].layY.loc]; IF routing#NIL THEN Include[obj: routing, loc: refPos]; IF dp[row][col].devCells#NIL THEN Include[ obj: PWCore.Layout[dp[row][col].devCells[bit]], loc: [x: refPos.x+ dp[row][col].devBOff*dp.spec.layBusW, y: refPos.y]]; ENDLOOP; ENDLOOP; ENDLOOP; [ ] _ RefTab.Pairs[dp.wpo, IncludePins]; cell _ PW.CreateCell[instances: insts, name: name.Cat[".mask"], ir: dp.layIR]}; CreateRoutingObject: PROC[dp: DP.Form, row, col: INT] RETURNS[obj: DP.Object] = { data: CoreClasses.RecordCellType _ NARROW[dp.cell.data]; nodes: LIST OF CDRoutingObjects.Node; action: RefTab.EachPairAction = { name: IO.ROPE _ CoreRoute.LabelInternal[data.internal, NARROW[key]]; node: CDRoutingObjects.Node; pos: DP.PObjs _ NARROW[val]; FOR ps: DP.PObjs _ pos, ps.rest WHILE ps#NIL DO ir _ CDBasics.Surround[ ir, CDBasics.MoveRect[CD.InterestRect[ps.first.object], ps.first.position]] ENDLOOP; node _ CDRoutingObjects.CreateNode[pos, LIST [[key: $SignalName, val: name]]]; nodes _ CONS[node, nodes]}; ir: CD.Rect _ [x1: 0, y1: 0, x2: 1, y2: 1]; -- need to begin at 0,0 for easy positioning of object IF RefTab.GetSize[dp[row][col].wpo]=0 THEN RETURN[NIL]; [ ] _ RefTab.Pairs[dp[row][col].wpo, action]; obj _ CDRoutingObjects.CreateRoutingObject[nodes, ir]}; GetDeviceCellTypes: PROC[inst: DP.CellInstance] RETURNS[cells: DP.CellTypeSeq] = { cells _ NEW[DP.CellTypeSeqRec[GetSize[inst.type]]]; FOR i: NAT IN [0..cells.size) DO cells[i] _ GetChild[inst.type, i] ENDLOOP}; GetChild: PROC[cell: DP.CellType, bit: INT] RETURNS[child: DP.CellType] = { WITH cell.data SELECT FROM seq: CoreClasses.SequenceCellType => RETURN[seq.base]; rec: CoreClasses.RecordCellType => RETURN[rec[bit].type]; ENDCASE => RETURN[GetChild[ CoreOps.Recast[cell], bit]]}; GetSize: PROC[cell: DP.CellType] RETURNS[size: INT] = { WITH cell.data SELECT FROM seq: CoreClasses.SequenceCellType => RETURN[seq.count]; rec: CoreClasses.RecordCellType => RETURN[rec.size]; ENDCASE => RETURN[GetSize[ CoreOps.Recast[cell]]]}; ShowDP: PUBLIC PROC[dp: DP.Form] = { TerminalIO.PutF["Data Path Rows: %g\n", IO.rope[CoreOps.GetCellTypeName[dp.cell]]]; FOR row: NAT DECREASING IN [0..dp.size) DO mux: BOOL _ FALSE; name: DP.ROPE _ NIL; TerminalIO.PutF["%3g x1:%5g x2:%5g y1:%5g y2:%5g", IO.int[row], IO.int[dp[row].schIR.x1], IO.int[dp[row].schIR.x2], IO.int[dp[row].schIR.y1], IO.int[dp[row].schIR.y2] ]; FOR col: INT IN [0..dp[row].size) DO IF dp[row][col].schInst=NIL THEN LOOP; mux _ IsMux[dp[row][col].schInst.type]; name _ CoreOps.GetCellTypeName[dp[row][col].schInst.type]; EXIT ENDLOOP; SELECT TRUE FROM dp[row].ch # NIL => TerminalIO.PutF[" \tChan\t\t"]; mux => TerminalIO.PutF[" \tMux\t"]; ENDCASE => TerminalIO.PutF[" \t\t\t"]; TerminalIO.PutF["%g\n", IO.rope[name]]; ENDLOOP}; IsMux: PROC[cell: DP.CellType] RETURNS[isMux: BOOL] = {RETURN[PWCore.GetLayoutAtom[GetChild[cell, 0]]=$DataPathMux]}; CountTransistors: PUBLIC PROC[cell: DP.CellType] RETURNS[count: INT _ 0] = { IF cell=NIL THEN RETURN[0]; SELECT cell.class FROM CoreClasses.transistorCellClass => RETURN[1]; CoreClasses.sequenceCellClass => { data: CoreClasses.SequenceCellType _ NARROW[cell.data]; count _ data.count*CountTransistors[data.base]}; CoreClasses.recordCellClass => { data: CoreClasses.RecordCellType _ NARROW[cell.data]; FOR child: NAT IN [0..data.size) DO count _ count + CountTransistors[ data.instances[child].type ] ENDLOOP }; ENDCASE => count _ CountTransistors[CoreOps.Recast[cell]] }; RegisterDataPathSpec: PUBLIC PROC[key: IO.ROPE, spec: DP.DPSpec] = {[] _ SymTab.Store[dpKeyTab, key, spec]}; NewCellTypeSpec: PUBLIC PROC[cellType: DP.CellType] RETURNS[spec: DP.DPSpec] = { key: IO.ROPE _ NARROW[CoreProperties.GetCellTypeProp[cellType, $DataPathKey]]; spec _ NEW[DP.DPSpecRec _ FetchDataPathSpecRec[key]]}; FetchDataPathSpecRec: PROC[key: IO.ROPE] RETURNS[spec: DP.DPSpecRec] = { family: IO.ROPE _ key.Substr[0, key.Index[0,"-"]]; busRp: IO.ROPE _ key.Substr[key.Index[0,"-"]+1]; buses: INT _ Convert.IntFromRope[busRp]; sp: DP.DPSpec _ NARROW[SymTab.Fetch[dpKeyTab, family].val]; spec _ sp^; spec.buses _ buses; IF spec.gndBus#-1 THEN spec.gndBus _ spec.gndBus+buses; IF spec.vddBus#-1 THEN spec.vddBus _ spec.vddBus+buses}; InitDataPathDP8: PROC = {RegisterDataPathSpec["DP", NEW[DP.DPSpecRec _ [ ]]]}; InitDataPathDP8[]; [] _ PWCore.RegisterLayoutAtom[$DataPath, Layout]; END. ,DataPathLayout.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Don Curry, November 10, 1987 12:46:04 pm PST Last Edited by: Gasbarro November 11, 1987 7:48:44 pm PST Signals and constants Layout Proc Build Interval Lists TerminalIO.PutF["Layout %g\n", IO.rope[CoreOps.GetCellTypeName[cellType]]]; Examine Interval Lists Build dp: DataPath, row - column array Find section instances Make Device Layouts Make Channel Layouts Set Layout IR Make Device Wiring Layouts then Complete Layout Interval Utils Routing Geometry Enumeration IF CoreOps.GetShortWireName[w].Equal["CryInTerm"] THEN TerminalIO.PutRope["Dubug Here\n"]; Add Bit routing and contacts Coordinate Utils sides[right] _ schIR.x2=externalIR.x2-externalIR.x1; sides[top] _ schIR.y2=externalIR.y2-externalIR.y1}; Ck both layers/sides Positioned Object Utils IF ~rtEdge AND (rBus MOD 2)=0 THEN Signal[]; Assembly obj _ CDRoutingObjects.CreateRoutingObject [nodes, [0, 0, (dp.spec.buses)*dp.spec.layBusW, dp[row].layY.size]]}; Show DataPath DataPath Spec Registration Initialization Κ%Ι˜šœ™Jšœ Οmœ1™JšΟb™Jšœžœ*™Kšžœžœžœž˜#Jšœžœ˜$Jšœžœ˜Jšœ-˜-Jšœ2Οc˜QJšœS˜SJšœA˜AJšžœ˜—Jšœ  œ œ  ˜;Jš ™š žœžœ#žœžœž˜@Jšœ˜Jšœ žœ'žœ-˜ešžœ žœžœ8žœ˜XJšžœ#žœžœžœ˜R——š žœžœ%žœžœž˜BJšœ˜Jšœ žœ'žœ-˜eJš žœ žœžœ8žœ žœ˜b—š žœžœ#žœžœž˜@Jšœ˜Jšœ žœ'žœ-˜eJš žœ žœžœ8žœ žœ˜b—Jš &™&Jšœžœžœ˜!Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšžœžœžœ ˜9Jšœ˜šžœžœž˜Jš œžœžœžœžœžœ-˜^Jšœ žœžœ˜%Jšœ˜šžœ˜šžœ˜Jšœ˜Jšœ*˜*JšœD˜DJšœ"˜"—šžœ˜Jšœ(˜(Jšœ@˜@Jšœ˜——Jšœ˜š žœžœ$žœžœž˜CJšœ(˜(Jšœ;˜;Jšœ)˜)Jšœ)˜)Jšžœžœ$˜/Jšœ žœ˜—Jšžœ˜—Jš ™šžœžœžœž˜#Jšœ-˜-šžœž œžœž˜%Jš žœžœžœžœžœ žœ˜K—šžœž œžœž˜*Jš žœ žœžœžœžœ žœ˜P—Jšžœžœžœ ˜*Jšœ.˜.Jšžœ2žœžœ ˜MJšœI˜IJšžœ˜—Jšœ ˜ Jš ™šžœžœž˜š žœ žœžœžœžœž˜6Jšžœžœžœžœ˜&JšœA˜AJšœX˜XJšžœžœ˜——Jš ™Jšœ˜Jšœ˜Jšžœžœžœžœ žœžœžœžœ˜PJš  Πbk™ šžœžœž˜Jšœ:žœ˜B—šœ ˜ Jšœ5˜5Jšœ<˜<—Jš /™/Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ˜Jšœ œ˜"Jšœ!žœ)˜LJšœ&žœ!˜IJšœ ˜ šœE˜EJšžœžœ#˜,Jšžœžœ#˜,Jšžœžœ$žœ'˜W———š œ™š Πbnœžœžœžœžœ ˜NJšžœ žœ žœ˜&Jšœ#žœ ˜5šŸ œžœžœ˜Jšœžœ˜š žœžœžœžœž˜;šžœ˜JšžœBžœ˜N—Jšžœ(žœžœ˜6Jšœ(˜(Jšžœžœ?žœ˜W——šœ˜Jšœžœžœ#˜HJšœžœ,˜6Jšœžœ˜%Jšžœžœ˜—Jšœžœžœ5˜Hšžœžœžœž˜#Jšœ žœ ˜Jšœ-˜-Jšœžœ˜&—Jš œ˜3J˜—š Ÿœžœžœžœ žœ žœ˜`Jšœ žœ˜šžœžœžœž˜4Jšœžœžœ žœ ˜1Jš žœ žœžœ*žœžœ˜KJšžœ"žœ"žœ˜Ršžœ*žœžœ+˜^Jšžœž˜ JšžœS˜W—JšœR˜RJšžœ˜ ———šœ™J˜šœžœžœžœ#˜BJ˜—šŸœžœžœžœ žœžœžœžœ˜EJšœ žœ˜&J˜—šŸœžœžœ*˜VJšœ#žœ ˜5šŸœ˜/JšœK˜KKš žœ)žœžœžœžœ‘ ˜RJš žœ žœžœžœ žœ˜,šžœ$žœ žœž˜—J˜—šŸœžœžœ ˜2šœ˜Jšœžœžœ#˜IJšœžœ-žœ˜=Jšžœ%žœ ˜5Jš ™š žœžœžœžœžœž˜DJšžœ žœžœžœ˜šžœžœžœž˜-Jšœžœ4˜<šžœžœ˜šžœ žœž˜(š œ˜Jš œ,˜4——šžœ žœž˜(š œ˜Jš œ,˜4——š œ˜Jš œC˜J——šžœ žœ˜šžœ žœž˜)š œ˜Jš œ,˜4——šžœ žœž˜)š œ˜Jš œ,˜4——š œ˜Jš œ6˜=——Jšžœ˜—Jšžœ˜ ——Jšœ6˜6J˜—š£œžœžœ ˜3Jš  œ ˜%Jš œ œ‘$˜JJ˜—š£ œžœžœ ˜8šžœ žœžœžœžœ$žœ žœž˜Tšžœžœžœž˜Jšœ žœ˜ Jšœ žœ˜Jšœžœ ˜Jšœ ˜ Jšžœ žœžœžœ˜šžœžœž˜5Jšžœžœžœžœžœžœžœžœ˜J—JšœM˜MJšœ#˜#šœ˜JšœH˜H—šžœžœžœž˜(šžœžœžœž˜$šœžœžœž˜)Jšžœ˜Jšžœ˜—šœ&˜&JšœV˜V—Jšžœ˜—Jšžœ˜—Jšžœ˜—Jšžœ˜ —J˜—š£œžœžœ ˜7Jšœžœ0˜7Jšœžœ0˜7Jšžœžœžœ˜!Jšžœžœžœ˜ š žœžœž œžœž˜*Jšœžœ˜Jšžœ žœžœžœ˜š žœžœž œžœž˜/Jšžœžœžœžœ˜&šœ˜JšœA˜A—šœ˜JšœA˜A—Jšžœžœ˜——J˜—šŸœžœžœ ˜-JšœžœP˜ZJšœžœR˜\šœ˜Jšœžœžœ#˜IJšœžœ-žœ˜=šžœ!žœ˜)Jš œžœ žœ žœžœ˜6š žœžœžœžœž˜Jšœžœ ˜Jšžœžœžœžœ˜#š žœ žœ žœžœžœžœž˜AJš œžœžœ žœžœ˜/šœžœž˜Jšœ ˜ Jšœžœžœžœ˜<—šœ*˜*JšœH˜H—Jšœ!˜!Jšœ˜Jšžœ˜—šžœ žœ žœ˜!Jš œžœžœ žœžœ˜,šžœžœžœ ž˜Jš œžœžœ žœžœ˜.šœžœžœž˜&Jšžœžœ'˜.Jšžœ ˜—Jš žœžœžœ žœžœ˜3šœžœž˜Jšœ ˜ Jšœžœ˜.Jšžœžœ˜—Jšœ;˜;Jšžœžœžœ˜)Jšœ!˜!Jšœ˜Jšžœ˜ ——Jšžœ˜ ———Jšœ6˜6J˜—š£œžœžœ ˜0Jš œ˜Jš œ˜J˜—š£œžœžœ ˜3Jšœžœ ˜Jšœžœ˜šžœžœžœž˜šžœ žœžœžœžœ$žœ žœž˜TJšœžœ ˜Jšœžœ˜Jšœ žœ8˜CJšœ˜šžœ ž˜šžœ˜Jšœ ˜ Jšžœžœ)žœžœ˜9Jšœ žœK˜YJšœžœžœ˜Jšœžœžœ˜—šžœ˜šžœ žœžœž˜:Jšžœžœžœžœ˜)Jšœ$˜$Jšœ5˜5Jšœ;˜;Jš žœžœžœžœžœ˜&—šžœ žœžœ ž˜=Jšžœžœžœžœ˜)Jšœ#˜#Jšœ4˜4JšœR˜RJš žœžœžœžœžœ˜'———šžœžœžœž˜/JšœO˜OJšœ,˜,Jšœ&˜&Jšœ žœ˜(—šžœžœžœž˜/JšœO˜OJšœ1žœ8˜kJšœ%˜%Jšœ žœ˜(—Jšžœ˜—Jšžœ˜ —J˜—š£œžœžœ ˜2Jšœžœ0˜7Jšœžœ0˜7JšœžœP˜WJšœžœ˜ Jšžœžœžœ˜!Jšžœžœžœ˜ šž˜Jšœžœ7žœ˜YJšœžœ˜šžœžœžœž˜$šžœžœžœž˜!šœžœ(˜1Jšœ6žœ˜O—šœžœ(˜1Jšœ6žœ˜O—šžœžœ˜JšœQ˜QJšœR˜R—šžœžœ˜JšœQ˜QJšœQ˜Q—Jšž˜——Jš žœžœžœžœžœ˜;———™Jšœžœžœžœ˜Jšœžœžœ žœ˜%šœžœ˜J˜—š Ÿœžœžœžœ žœ žœ˜?Jšœžœ,˜3J˜—šŸœžœžœžœžœžœžœ˜Jšœ.žœ˜@Jšžœžœ˜&Jšžœžœ!˜*—Jšœ žœ˜ Jšžœ@˜FJ˜—š Ÿ œžœžœžœžœ ˜8šœ ˜ J˜J˜J˜*Jšœ+˜+—J˜—š Ÿœžœžœ žœžœžœ ˜Ašœ ˜ Jšœ˜Jšœ˜Jšœ$˜$Jšœ%˜%—J˜—šŸœžœžœžœ˜6Jšžœžœ ˜Jšœ žœžœ8˜PJšœ.˜.Jšœ0˜0Jšœ/˜/Jšœ/˜/Jšœ4™4Jšœ4™4J™—š Ÿ œžœžœžœžœ˜9JšœR˜Ršžœžœž˜Jšœ žœ˜Jšœ žœ˜Jšžœžœ‘˜+—J˜—š Ÿœžœžœ žœžœžœ˜WJšžœžœ˜Jšžœžœ ˜Jšœžœžœ!˜GJšœ,˜,Jšœ ˜ šžœžœžœž˜Jš œžœžœžœŸœ˜Ošžœžœ žœž˜(JšœJžœ˜V—šžœžœžœž˜$šžœ˜Jšœ4žœ žœ ˜Nšœ:˜:Jšžœžœžœžœ˜H—Jšžœ˜—š Ÿœžœžœžœ žœ žœ ˜CJšœ‘™Jšœžœ ž˜šžœžœ ž˜$Jšžœžœ4˜?—šžœ žœžœž˜Jš œžœžœžœžœ˜EJš œžœžœ žœžœ˜+š žœžœžœžœž˜;Jšžœžœžœžœ˜%šžœžœ‘˜,JšœI˜IJšžœžœž œ8˜NJšœžœžœ žœ ˜:Jšžœžœžœžœ˜ ————Jšœžœžœ˜Jš œ žœžœžœ.žœ˜TJš œ žœžœžœžœ˜Qšžœžœž˜Jšžœžœ)‘˜HJšœžœ˜ Jšœžœ‘˜3Jšœžœ‘˜2Jšœžœ‘˜7Jšœžœ ‘˜;Jšžœžœ˜—šžœžœ#ž˜2Jšœžœ#žœžœ˜H—J˜šžœ žœ-žœ˜AJšœ˜Jšœ˜—šžœ žœ:žœ˜NJšœ˜Jšœ   œ*˜@—šžœ žœ:žœ˜NJšœ˜Jšœ   œ*˜@—šžœ1žœ˜9Jšœ˜Jšœ˜—J˜šžœ žœ4žœ˜HJšœ˜Jšœ ˜ —šžœ žœ3žœ˜GJšœ˜Jšœ& œ˜G—šžœ žœ3žœ˜GJšœ˜Jšœ% œ˜G—šžœ-žœ˜5Jšœ˜Jšœ žœžœžœ˜O—Jšžœ˜—Jšžœ˜ —J˜—š Ÿœžœžœžœžœ˜HJšžœžœ˜Jšœ ˜ Jšžœžœ˜(Jšžœžœ˜5Jšžœžœ ˜'Jšžœžœ˜7Jšœ˜Jšœ˜J˜—šŸœž˜š œžœžœžœžœžœ˜OJšžœ˜—š£œžœžœ˜=Jšžœ žœžœ˜0š žœžœžœžœ žœž˜6Jš£œžœ˜2——Jšœ žœ?˜KJšœ žœ˜Jšœ žœ˜(Jšžœ žœžœ ˜Jš£œ*˜AJšžœ žœžœ ˜ Jšžœ:˜@J˜—šŸœž˜š œ žœžœžœ žœ˜GJšžœ žœžœ˜"—šœ&˜&Jšœ ˜ Jšžœžœžœ˜%Jšœ<˜<šžœžœžœž˜(Jšžœžœžœžœ˜7Jš žœžœžœ žœžœ˜2—Jšœžœžœ˜)—JšœJ˜JJ˜—šŸœž˜š œžœžœžœ žœ žœ˜SJšžœ žœ˜—šœ%˜%Jšžœžœžœžœ˜/Jšœžœ˜&—Jš œ&žœžœžœ žœ ˜WJš žœžœžœžœžœ˜JšœA˜AJ˜—š Ÿœžœžœžœ žœ˜HJšœžœ;˜BJšœJ˜JJšœžœ˜Jšœ+žœ˜Išžœžœ˜!Jšœžœ 3œžœ2˜{—J˜—šŸ œžœžœžœžœžœžœ˜HJšžœ˜——™šŸœžœ žœ žœ ˜/Jšœ8˜8Jšœ&žœ˜2J˜—šŸœžœžœžœ žœžœžœ ˜YJšœ?˜?Jšœ9žœ˜XJšœžœ˜7J˜—š Ÿœžœžœ!žœ žœ˜LJšžœžœ ˜Jšœžœ˜Jšœ žœ ˜Jšœ žœ˜%Jš œžœžœžœžœ+˜KJš œžœžœžœžœ+˜NJšžœ žœžœžœ ™,Jšžœ žœ ˜Jšœ=˜=Jšœ#˜#J˜—š Ÿœžœžœ žœ žœ˜FJšžœžœ ˜Jšžœžœ ˜$JšœK˜KJšœ@˜@Jšœ˜J˜—šŸœžœžœ žœ ˜>Jšœžœ žœ˜4Jšœžœ ˜Jšœ#˜#——š œ™š £œžœžœžœžœ ˜>šŸ œ˜&Jšœžœ žœ˜Jšœžœžœ*žœ˜Dšžœžœžœž˜(Jšœ.˜.Jšœ5žœ˜>——šŸœžœžœžœ˜3Jšžœžœžœžœ˜Jšœžœ˜4Jšœžœžœžœ&˜:—Jšœ#žœ˜8Jšœžœžœ$˜1Jšœžœžœ˜šžœžœžœž˜šžœ žœžœ˜Jšœ-žœ˜3—šžœžœžœž˜$Jšœ žœ,˜7šžœžœžœž˜!Jšœžœ?˜IJšžœ žœžœ$˜7šžœžœžœ ˜*Jšœ/˜/JšœG˜G—Jšžœ˜—Jšžœ˜—Jšžœ˜—Jšœ(˜(JšœžœF˜OJ™—š Ÿœžœžœžœžœžœ ˜QJšœ$žœ˜9Jšœžœžœ˜&šœ!˜!Jšœžœžœ*žœ˜DJšœ˜Jšœžœ žœ˜š žœžœžœžœžœ˜KJšœžœ4žœ˜P—Jšœ(žœ"˜NJšœžœ˜—Jšœžœ&‘6˜bJšžœ$žœžœžœ˜7Jšœ-˜-Jšœ7˜7šœ*™*JšœE™E—J˜—šŸœžœžœ˜/Jšžœžœ˜"Jšœžœžœ%˜3Jš žœžœžœžœ#žœ˜LJ˜—š Ÿœžœžœžœžœžœ˜Kšžœ žœž˜Jšœ%žœ ˜6Jšœ#žœ˜9Jšžœ žœ(˜A—J˜—š Ÿœžœžœ žœžœ˜7šžœ žœž˜Jšœ%žœ ˜7Jšœ#žœ ˜4Jšžœ žœ"˜;———šœ ™ šŸœžœžœžœ ˜$Jšœ(žœ)˜Sš žœžœž œžœž˜*Jšœžœžœ˜Jšœžœžœžœ˜˜6Jšžœ ˜ Jšžœ˜Jšžœ˜Jšžœ˜Jšžœ˜—šžœžœžœž˜$Jšžœžœžœžœ˜&Jšœ'˜'Jšœ:˜:Jšžœžœ˜ —šžœžœž˜Jšœ žœ$˜4Jšœ(˜(Jšžœ#˜*—Jšœžœ ˜'Jšžœ˜ —J˜—š Ÿœžœžœ žœžœ˜5Jšœžœ8˜?J˜—š Ÿœžœžœžœ žœžœ ˜LJšžœžœžœžœ˜šžœ ž˜Jšœ#žœ˜-šœ#˜#Jšœ%žœ ˜7Jšœ0˜0—˜!Jšœ#žœ ˜5šžœžœžœž˜#Jšœ?žœ˜I——Jšžœ;˜B———šœ™š Ÿœžœžœžœžœžœ ˜BJšœ)˜)J˜—š Ÿž œ žœ žœžœ ˜PJšœžœžœžœ9˜NJšœžœžœ)˜6J˜—š Ÿœžœžœžœžœžœ˜HJšœžœžœ$˜3Jšœžœžœ#˜1Jšœžœ ˜+Jšœžœ žœ%˜=Jšœ˜Jšœ˜Jšžœžœ!˜7Jšžœžœ"˜8——šœ™šŸœžœ˜Jšœžœžœ˜6J˜—Jšœ˜J˜Jšœ2˜2J˜—Jšžœ˜J˜K™—…—yΦ£Λ