DIRECTORY Basics, CD, CDBasics, CDDirectory, CDProperties, CDRects, CDRoutingObjects, CDSimpleRules, CMosB, Core, CoreClasses, CoreCreate, CoreGeometry, CoreOps, CoreProperties, CoreXform, DP, RefTab, IO, PW, PWCore, Rope, Sisyph, TerminalIO; DPLayout: CEDAR PROGRAM IMPORTS Basics, CD, CDBasics, CDDirectory, CDProperties, CDRects, CDRoutingObjects, CDSimpleRules, CMosB, CoreClasses, CoreCreate, CoreGeometry, CoreOps, CoreProperties, CoreXform, DP, RefTab, IO, PW, PWCore, Rope, Sisyph, TerminalIO EXPORTS DP SHARES CDRects = BEGIN 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; Layout: PWCore.LayoutProc ~ { data: CoreClasses.RecordCellType _ NARROW[cellType.data]; spec: DP.DPSpec _ NARROW[CoreProperties.GetProp[cellType.properties, $DPSpec].value]; schIR: CD.Rect _ [x1: LAST[INT], x2: FIRST[INT], y1: LAST[INT], y2: FIRST[INT]]; xIntervals: DP.Intervals _ NIL; yIntervals: DP.Intervals _ NIL; yIntervalsSB: DP.Intervals _ NIL; colChans: NAT _ spec.chans*DP.schChanW; count: NAT _ 0; nofRows: NAT _ 0; nofCols: NAT _ 0; row: NAT _ 0; col: NAT _ 0; transistors: INT _ 0; dp: DP.DataPath _ NIL; loc: CD.Position; size: CD.Position; FOR child: NAT IN [0..data.size) DO count: INT _ CountTransistors[data.instances[child].type]; IF count=0 THEN {TerminalIO.PutF["Warning: Zero transistor celltype: %g\n", IO.rope[CoreOps.GetCellTypeName[data.instances[child].type]]]}; transistors _ transistors + count; [loc, size] _ LocSize[data.instances[child]]; IF size.x=(spec.dChans*DP.schChanW) THEN xIntervals _ InsertInterval[[loc.x-colChans, size.x+colChans], xIntervals] ELSE xIntervals _ InsertInterval[[loc.x, size.x], xIntervals]; yIntervals _ InsertInterval[[loc.y, size.y], yIntervals]; ENDLOOP; yIntervalsSB _ FindSBIntervals[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 _ yIntervalsSB, 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; IF dp.spec.xforms = NIL THEN dp.spec.xforms _ LIST[[dp.spec.cols, 0], [dp.spec.n, 1]]; FOR row IN [0..dp.size) DO sb: BOOL _ yIntervals=NIL OR yIntervalsSB#NIL AND yIntervalsSB.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]; dp[row][col].devCells _ GetDeviceCellTypes[dp, data.instances[child]]; IF (SchHalfChan[loc.x - dp[row][col].schIR.x1] MOD 2) # 0 THEN Signal[]; dp[row][col].devCOff _ SchHalfChan[loc.x - dp[row][col].schIR.x1]/2; dp[row].layY.size _ CDBasics.SizeOfRect[PWCore.InterestRect[dp[row][col].devCells[0]]].y ENDLOOP; InitRouting[dp]; 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]*dp.spec.cols*dp.spec.n, y1: 0, y2: dp[dp.size-1].layY.loc+dp[dp.size-1].layY.size ]; AddSchematicGeometry[dp]; AddGlobalRoutingInformation[dp]; obj _ dp.obj _ AssembleObject[dp]; TerminalIO.PutF["\nLayout %g\n", IO.rope[CoreOps.GetCellTypeName[cellType]]]; TerminalIO.PutF[" %g transistors\n", IO.int[transistors]]; ShowDP[dp]; TerminalIO.PutF["Layout Size (lambda) x: %g y: %g xy: %g\n", IO.int[CD.InterestSize[obj].x/DP.lambda], IO.int[CD.InterestSize[obj].y/DP.lambda], IO.int[(CD.InterestSize[obj].x/DP.lambda)*(CD.InterestSize[obj].y/DP.lambda)] ]}; InitRouting: PROC[dp: DP.DataPath] = { gnd: DP.Wire = CoreOps.FindWire[dp.cell.public, "Gnd"]; vdd: DP.Wire = CoreOps.FindWire[dp.cell.public, "Vdd"]; FOR row: INT DECREASING IN [0..dp.size) DO ytop: INT _ dp[row].layY.size; FOR col: INT DECREASING IN [0..dp[row].size) DO dp[row][col].wpo _ RefTab.Create[]; IF dp[row].sb#NIL THEN LOOP; IF dp[row][col].schInst=NIL THEN { AddPObj[dp[row][col].wpo, gnd, VerPObj[0, ytop, (dp.spec.chans+1)*2-1, DP.pwrW]]; AddPObj[dp[row][col].wpo, vdd, VerPObj[0, ytop, (dp.spec.chans+2)*2-1, DP.pwrW]]}; ENDLOOP ENDLOOP}; BitWidth: PUBLIC PROC[dp: DP.DataPath] RETURNS[bitWidth: INT] = {RETURN[(dp.spec.chans+ dp.spec.dChans)*DP.layChanW]}; EachWireInst: TYPE = PROC[w: DP.Wire, geo: CoreGeometry.Instance]; EnumInternalSchematicGeometry: PROC[cell: DP.CellType, eachWireInst: EachWireInst] = { data: CoreClasses.RecordCellType _ NARROW[cell.data]; EnumSchematicGeometry: CoreOps.EachWireProc ~ { geometry: CoreGeometry.Instances _ CoreGeometry.GetGeometry[schDeco, wire]; IF geometry=NIL THEN RETURN[subWires: TRUE]; FOR geometry _ geometry, geometry.rest WHILE geometry#NIL DO eachWireInst[wire, geometry.first] ENDLOOP; RETURN[subWires: TRUE]}; []_CoreOps.VisitWire[data.internal, EnumSchematicGeometry]}; FindSBIntervals: PROC[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) >= DP.schChanW/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]}; AddSchematicGeometrySB: PROC[dp: DP.DataPath] = { 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].sb#NIL THEN DP.AddSBNode[dp, row, w, lc]; ENDLOOP}; EnumInternalSchematicGeometry[dp.cell, eachWireInst]}; AddSchematicGeometry: PROC[dp: DP.DataPath] = { 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].sb#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.chanLt IN [1..dp.spec.chans*2) THEN AddPObj[dp[row][col].wpo, w, ContPObj[lc.chanLt, lc.yTop, lc.horLayTop]]; IF lc.chanRt IN [1..dp.spec.chans*2) THEN AddPObj[dp[row][col].wpo, w, ContPObj[lc.chanRt, lc.yTop, lc.horLayTop]]; AddPObj[dp[row][col].wpo, w, HorPObj[lc.yTop, lc.chanLt, lc.chanRt, 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[lc.chanLt, lc.yBot, lc.horLayBot]]; IF lc.yTop IN (0..dp[row].layY.size) THEN AddPObj[dp[row][col].wpo, w, ContPObj[lc.chanLt, lc.yTop, lc.horLayTop]]; AddPObj[dp[row][col].wpo, w, VerPObj[lc.yBot, lc.yTop, lc.chanLt]]}; ENDLOOP; ENDLOOP; 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]; xform: CoreXform.Xform _ CoreXform.GenXform[dp.spec.xforms]; logical: INT _ bigLC.colLt*dp.spec.n + bit; loc.y _ SELECT side FROM bottom => 0, top => dp.layIR.y2 - CD.InterestSize[tag].y ENDCASE=>ERROR; loc.x _ BitWidth[dp] * CoreXform.XformIndex[xform, lr, logical].i + DP.leftTail + (bigLC.chanLt-1)*DP.layChanW/2 - DP.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].sb#NIL THEN DP.GetSBY[dp[bigLC.rowBot].sb, kid].loc ELSE bigLC.yBot; IF dp[bigLC.rowBot].sb=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; AddPObj[dp.wpo, kid, [tag, loc]]; AddPin[ kid, [tag, loc]]; ENDLOOP}; ENDLOOP } }; EnumInternalSchematicGeometry[dp.cell, eachWireInst]}; GetGlobalNames: PROC[dp: DP.DataPath] RETURNS[globals: LIST OF DP.ROPE] = {globals _ LIST["Gnd", "Vdd", "Vbb"]}; AddGlobalRoutingInformation: PROC[dp: DP.DataPath] = { 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].sb#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 _ dp.spec.chans + (IF dp[row][refCol].schInst=NIL THEN dp.spec.dChans ELSE 0); AddPObj[ dp[row][col].wpo, actualWire, HorPObj[lss.first.loc+lss.first.size/2, 0, cWidth*2, lss.first.size, CMosB.met2] ]; ENDLOOP; ENDLOOP; ENDLOOP; ENDLOOP; AddGlobalSideDecorations[dp]; AddGlobalEndDecorations[dp]}; tagVer: DP.Object _ CDRects.CreateRect[ [x: DP.metW, y: DP.pinSize], CMosB.met]; tagHor: DP.Object _ CDRects.CreateRect[ [x: DP.pinSize, y: DP.met2W], CMosB.met2]; AddGlobalSideDecorations: PROC[dp: DP.DataPath] = { 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].sb#NIL THEN { lss: LSRec; IF NOT RefTab.Fetch[dp[row].sb, actWire].found THEN LOOP; lss _ [loc: DP.GetSBY[dp[row].sb, actWire].loc - DP.met2W/2, size: DP.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.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.pinSize, y: lss.first.size], CMosB.met2]; loc _ [dp.spec.cols*dp.spec.n*BitWidth[dp]- CD.InterestSize[tag].x, dp[row].layY.loc + lss.first.loc]; AddPObj[dp.wpo, actWire, [tag, loc]]; AddPin[ actWire, [tag, loc]] ENDLOOP; ENDLOOP; ENDLOOP}; pwrSep: INT _ 1; AddGlobalEndDecorations: PROC[dp: DP.DataPath] = { 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.pwrW, y: DP.pinSize], CMosB.met]; FOR row: INT _ 0, row+dp.size-1 WHILE row< dp.size 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: NAT IN [0..dp.spec.n) DO gndx: INT _ BitWidth[dp]*(col*dp.spec.n+bit) + dp.spec.chans*DP.layChanW + DP.leftTail - CD.InterestSize[tag].x/2; vddx: INT _ gndx + pwrSep*DP.layChanW; 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 ENDLOOP}; BitPosX: PUBLIC PROC[dp: DP.DataPath, col, bit: NAT] RETURNS[pos: INT] = { xform: CoreXform.Xform _ CoreXform.GenXform[dp.spec.xforms]; logical: INT _ col*dp.spec.n + bit; RETURN[BitWidth[dp] * CoreXform.XformIndex[xform, lr, logical].i ]}; slop: INT _ DP.schChanW/4; GetInBodyIR: PROC[dp: DP.DataPath, schIR: CD.Rect] RETURNS[BOOL] = { schBodyIR: CD.Rect _ [ 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]; RETURN[CDBasics.Intersect[schIR, CDBasics.Extend[schBodyIR, -1]]]}; GetLayoutCoordSides: PROC[dp: DP.DataPath, 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.DataPath, wire: DP.Wire, schIR: CD.Rect, initialLayYSize: BOOL] RETURNS[lc: DP.LayoutCoord] = { lc.inBody _ GetInBodyIR[dp, schIR]; lc.sides _ GetLayoutCoordSides[dp, schIR]; lc.hor _ GetLayoutHor[schIR]; FOR row: NAT IN [0..dp.size) DO FOR col: NAT IN [0..dp[row].size) DO OPEN CDB: CDBasics; 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].sb#NIL THEN RETURN[DP.initialYSize/2, DP.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; 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 [dp[row][col].schIR.x1-slop..dp[row][col].schIR.x1+slop) THEN { lc.colLt _ col; lc.chanLt _ 0}; IF schIR.x1 IN [dp[row][col].schIR.x1+slop..dp[row][col].schIR.x2-slop) THEN { lc.colLt _ col; lc.chanLt _ SchHalfChan[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.chanRt _ SchHalfChan[schIR.x2-dp[row][col].schIR.x1]}; IF schIR.x2 >= dp[row][col].schIR.x2-slop THEN { lc.colRt _ col; lc.chanRt _ SchHalfChan[dp[row][col].schIR.x2-dp[row][col].schIR.x1]}; 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.initialYSize ELSE dp[row].layY.size}; ENDLOOP; ENDLOOP}; TrimLayoutCoord: PROC[dp: DP.DataPath, bigLC: DP.LayoutCoord, row, col: NAT] RETURNS[lc: DP.LayoutCoord] = { lc _ bigLC; IF col > bigLC.colLt THEN lc.chanLt _ 0; IF col < bigLC.colRt THEN lc.chanRt _ (dp.spec.chans+ dp.spec.dChans)*2; 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 }; AddPin: PROC [public: DP.Wire, po: DP.PObj] = { pin: CoreGeometry.Instance _ [po.object, [po.position]]; CoreGeometry.AddPins[layDeco, public, LIST[pin]]}; IconToLayoutGeoLocSizes: PROC [sec: DP.Section, actual: DP.Wire, schLoc: INT, side: DP.Side, layer: CD.Layer] RETURNS[lss: LSs] = { iconPub: DP.Wire _ GetSchematicPublic[sec.schInst, actual, side, schLoc]; bitCellPub: DP.Wire; bitCell: DP.CellType _ sec.devCells[0]; name: DP.ROPE; IF iconPub=NIL THEN DrawingError[]; name _ CoreOps.GetShortWireName[iconPub]; IF name=NIL THEN name _ DP.GetCharCode[iconPub]; bitCellPub _ CoreCreate.FindWire[bitCell.public, name]; 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]}; LSs: TYPE = LIST OF LSRec; LSRec: TYPE = RECORD[loc, size: INT]; 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]}; SchHalfChan: PUBLIC PROC[pos: INT] RETURNS[chan: INT] = { RETURN[pos/(DP.schChanW/2)]}; ContPObj: PROC[chan, layY: INT, layer: CD.Layer] RETURNS[po: DP.PObj] = { po.object _ CDSimpleRules.Contact[layRules, CMosB.met, layer]; po.position.x _ DP.leftTail + (chan-1)*DP.layChanW/2 - DP.cnctSize/2; po.position.y _ layY - DP.cnctSize/2}; HorPObj: PROC[layY, lChan, rChan, size: INT, layer: CD.Layer] RETURNS[po: DP.PObj] = { offSet: INT _ DP.leftTail-DP.layChanW/2; ltEdge: BOOL _ lChan = 0; rtEdge: BOOL _ rChan MOD 2 = 0; x1: INT _ DP.leftTail + (lChan-1) * DP.layChanW/2 - (IF ltEdge THEN offSet ELSE 0); x2: INT _ DP.leftTail + (rChan-1) * DP.layChanW/2 - (IF rtEdge THEN offSet ELSE 0); IF x1 >= x2 THEN Signal[]; po.object _ CDRects.CreateRect[ [x: x2-x1, y: size], layer]; po.position _ [x1, layY - size/2]}; VerPObj: PROC[layYbot, layYtop, chan: INT, size: INT _ DP.metW] RETURNS[po: DP.PObj] = { IF layYbot >= layYtop THEN Signal[]; po.object _ CDRects.CreateRect[ [x: size, y: layYtop-layYbot], CMosB.met]; po.position.x _ DP.leftTail + (chan-1)*DP.layChanW/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.DataPath] RETURNS[cell: DP.Object] = { IncludePins: RefTab.EachPairAction = { pos: DP.PObjs _ NARROW[val]; name: DP.ROPE _ CoreOps.GetFullWireName[dp.cell.public, 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] = { loc _ CDBasics.SubPoints[loc, CD.InterestBase[obj]]; -- for sb and mux offsets insts _ CONS[ NEW[CD.InstanceRep _ [obj, [loc]]], insts]}; name: DP.ROPE _ CoreOps.GetCellTypeName[dp.cell]; insts: CD.InstanceList _ NIL; xform: CoreXform.Xform _ CoreXform.GenXform[dp.spec.xforms]; FOR row: NAT IN [0..dp.size) DO IF dp[row].sb#NIL THEN { Include[dp[row].obj, [0, dp[row].layY.loc]]; LOOP}; FOR col: NAT IN [0..dp[row].size) DO routing: DP.Object _ CreateRoutingObject[dp, row, col, 0]; FOR bit: NAT IN [0..dp.spec.n) DO refPos: CD.Position _ [BitPosX[dp, col, bit] + 0, dp[row].layY.loc]; IF routing#NIL THEN Include[ obj: routing, loc: refPos ]; IF dp[row][col].schInst=NIL THEN LOOP; IF IsMux[dp[row][col].schInst.type] THEN { obj: CD.Object _ PWCore.Layout[dp[row][col].devCells[bit]]; new: CD.Object _ CDDirectory.Expand1[obj].new; IF new=NIL THEN ERROR; Include[obj: new, loc: [x: refPos.x, y: refPos.y ]]} ELSE Include[ obj: PWCore.Layout[dp[row][col].devCells[bit]], loc: [x: refPos.x+ dp[row][col].devCOff*DP.layChanW, 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.DataPath, row, col, bit: INT] RETURNS[obj: DP.Object] = { nodes: LIST OF CDRoutingObjects.Node; action: RefTab.EachPairAction = { node: CDRoutingObjects.Node; pos: DP.PObjs _ GetPObjs[val, bit]; node _ CDRoutingObjects.CreateNode[pos]; nodes _ CONS[node, nodes]}; IF RefTab.GetSize[dp[row][col].wpo]=0 THEN RETURN[NIL]; [ ] _ RefTab.Pairs[dp[row][col].wpo, action]; obj _ CDRoutingObjects.CreateRoutingObject[nodes, [0, 0, (dp.spec.chans)*DP.layChanW, dp[row].layY.size]]}; GetPObjs: PROC[value: REF, bit: INT] RETURNS[pos: DP.PObjs] = { WITH value SELECT FROM lopobjs: DP.PObjs => RETURN[lopobjs]; ENDCASE => ERROR}; GetDeviceCellTypes: PROC[dp: DP.DataPath, inst: DP.CellInstance] RETURNS[cells: DP.CellTypeSeq] = { IF IsMux[inst.type] THEN RETURN[DP.GetMuxCellTypes[dp, inst]]; cells _ NEW[DP.CellTypeSeqRec[dp.spec.n]]; FOR i: NAT IN [0..cells.size) DO cells[i] _ GetChild[inst.type, i] ENDLOOP}; IsMux: PROC[cell: DP.CellType] RETURNS[isMux: BOOL] = { rec: CoreClasses.RecordCellType; name: DP.ROPE _ CoreOps.GetCellTypeName[cell]; IF NOT ISTYPE[cell.data, CoreClasses.RecordCellType] THEN RETURN[FALSE]; IF name.Substr[MAX[0, name.Length-3], 3].Equal["Mux", FALSE] THEN RETURN[TRUE]; rec _ NARROW[cell.data]; RETURN[CoreOps.GetCellTypeName[rec[0].type].Equal["DP.DPMuxSwitch.icon"]]}; GetChild: PROC[cell: DP.CellType, bit: INT _ -1] RETURNS[child: DP.CellType] = { IF bit<0 THEN RETURN[cell]; -- -1 means no bitwise replication hierarchy 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]]}; 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] ] ] ] }}; 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}; ShowDP: PUBLIC PROC[dp: DP.DataPath] = { 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.spec.cols) 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].sb # NIL => TerminalIO.PutF[" \tSB\t\t"]; mux => TerminalIO.PutF[" \tMux\t"]; ENDCASE => TerminalIO.PutF[" \t\t\t"]; TerminalIO.PutF["%g\n", IO.rope[name]]; ENDLOOP}; 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]] }; Decorate: PWCore.DecorateProc ~ { }; [] _ PWCore.RegisterLayoutAtom[$DP, Layout, Decorate]; END. þDPLayout.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Don Curry, May 1, 1987 11:47:40 am PDT Build Interval Lists TerminalIO.PutF["Layout %g\n", IO.rope[CoreOps.GetCellTypeName[cellType]]]; TerminalIO.PutF[" %g transistors\n", IO.int[transistors]]; Examine Interval Lists Build dp: DataPath, row - column array Make Switchbox Layouts Make Device Layouts IF CountTransistors[data.instances[child].type]=0 THEN LOOP; Set Layout IR Make Device Wiring Layouts then Complete Layout IF CountTransistors[data.instances[child].type]#0 THEN LOOP; Add Bit routing and contacts Add Public Pins NextLeftIndexes: PROC[dp: DP.DataPath, col, bit: INT] RETURNS[atEdge: BOOL, collt, bitlt: INT] = { xform: CoreXform.Xform _ CoreXform.GenXform[dp.spec.xforms]; addr: CoreXform.Addr; logical: INT _ col*dp.spec.cols + bit; physical: INT _ CoreXform.XformIndex[xform, lr, logical].i; IF (physical_physical-1)=-1 THEN RETURN[TRUE,0,0]; addr _ CoreXform.XformIndex[xform, rl, physical].a; RETURN[FALSE, addr.first, addr.rest.first]}; collt, bitlt: NAT; atEdge: BOOL; [atEdge, collt, bitlt] _ NextLeftIndexes[dp, col, 1]; -- ???Bit???? IF atEdge THEN Signal[]; This can probably be made to work generally when the top/bot global position is unknown AddGlobalEndDecorationsOld: PROC[dp: DP.DataPath] = { 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; FOR row: INT _ 0, row+dp.size-1 WHILE row< dp.size DO xform: CoreXform.Xform _ CoreXform.GenXform[dp.spec.xforms]; FOR col: NAT IN [0..dp[row].size) DO cell: DP.CellType _ dp[row][col].devCells[0]; wire: DP.Wire _ CoreOps.FindWire[cell.public, globals.first]; act: DP.Wire _ CoreOps.FindWire[dp[row][col].schInst.actual, globals.first]; FOR bit: NAT IN [0..dp.spec.n) DO logical: INT _ col*dp.spec.n + bit; bitPosition: INT _ BitWidth[dp] * CoreXform.XformIndex[xform, lr, logical].i; IF row=0 THEN { lss: LSs _ GetGeometryLocSizes[cell, wire, bottom, CMosB.met]; FOR lss _ lss, lss.rest WHILE lss#NIL DO tag _ CDRects.CreateRect[ [x: lss.first.size, y: DP.pinSize], CMosB.met]; loc _ [bitPosition + dp[row][col].devCOff*DP.layChanW + lss.first.loc, 0]; AddPObj[dp.wpo, act, [tag, loc]]; AddPin[ act, [tag, loc]] ENDLOOP}; IF row=dp.size-1 THEN { lss: LSs _ GetGeometryLocSizes[cell, wire, top, CMosB.met]; FOR lss _ lss, lss.rest WHILE lss#NIL DO tag _ CDRects.CreateRect[ [x: lss.first.size, y: DP.pinSize], CMosB.met]; loc _ [bitPosition + dp[row][col].devCOff*DP.layChanW + lss.first.loc, 0]; loc.y _ dp[row-1].layY.loc + dp[dp.size-1].layY.size - tag.size.y; AddPObj[dp.wpo, act, [tag, loc]]; AddPin[ act, [tag, loc]] ENDLOOP}; ENDLOOP; ENDLOOP }; ENDLOOP; ENDLOOP}; sides[right] _ schIR.x2=externalIR.x2-externalIR.x1; sides[top] _ schIR.y2=externalIR.y2-externalIR.y1}; Ck both layers/sides CreateRoutingObject: PROC[dp: DP.DataPath, row, col, bit: INT, names: BOOL _ FALSE] RETURNS[obj: DP.Object] = { ir: CD.Rect; max: CD.Position _ [(dp.spec.chans)*DP.layChanW, dp[row].layY.size]; action: RefTab.EachPairAction = { FOR pos: DP.PObjs _ GetPObjs[val, bit], pos.rest WHILE pos#NIL DO -- min _ CDBasics.MinPoint[min, pos.first.position]; max _ CDBasics.MaxPoint [max, CDBasics.AddPoints[pos.first.position, CD.InterestSize[pos.first.object]]]; insts _ CONS[ NEW[CD.InstanceRep _ [pos.first.object, [pos.first.position]]], insts] ENDLOOP}; insts: CD.InstanceList _ NIL; IF RefTab.GetSize[dp[row][col].wpo]=0 THEN RETURN[NIL]; [ ] _ RefTab.Pairs[dp[row][col].wpo, action]; ir _ CDBasics.RectAt[[0, 0], max]; obj _ PW.CreateCell[instances: insts, name: NIL, ir: ir]}; pobjseq: DP.PObjSeq => RETURN[pobjseq[bit]]; Use rectangles on border to apply names and specify sides. (extentions, not overlayed). Ê%…˜šœ ™ Jšœ Ïmœ1™˜HJšœžœžœ ˜5Jšœžœ˜%Jšžœžœžœ˜—Jšœžœ?˜Hšžœžœžœž˜#Jšœ žœ ˜Jšžœ/žœžœ™——Jšœ6˜6—J˜šŸœžœžœ˜/šœ˜Jšœžœ?˜IJšœžœ-žœ˜=Jšžœ%žœ ˜5Jš ™š žœžœžœžœžœž˜DJšžœ žœžœžœ˜šžœžœžœž˜-Jšœžœ4˜:šžœžœ˜šžœ žœž˜)Jš œ œ$˜I—šžœ žœž˜)Jš œ œ$˜I—š œ˜Jš œ<˜C——šžœ žœ˜šžœ žœž˜)Jš œ œ$˜I—šžœ žœž˜)Jš œ œ$˜I—š œ˜Jš œ ˜'——Jšžœ˜—Jšžœ˜—Jš ™šžœ!žœ˜)Jš œžœ žœ žœžœ˜6š žœžœžœžœž˜Jšœžœ ˜Jšžœžœžœžœ˜#š žœ žœ žœžœžœžœž˜AJš œžœžœ žœžœ˜/Jšœ=˜=Jšœ žœ˜+šœžœž˜Jšœ ˜ Jšœ-žœžœ˜<—šœA˜AJšœžœžœžœ˜;—Jšœ!˜!Jšœ˜Jšžœ˜—šžœ žœ žœ˜!Jš œžœžœ žœžœ˜,šžœžœžœ ž˜Jš œžœžœ žœžœ˜.šœžœžœž˜&Jšžœžœ%˜,Jšžœ ˜—Jš žœžœžœ žœžœ˜3šœžœž˜Jšœ ˜ Jšœ.˜.Jšžœžœ˜—Jšœ;˜;Jšœ!˜!Jšœ˜Jšžœ˜ ——Jšžœ˜ ———šœ6˜6J˜——šŸœžœžœžœ™5Jšžœ žœžœ™,Jšœ=™=Jšœ™Jšœ žœ™&Jšœ žœ.™;Jšžœžœžœžœ™2Jšœ3™3Jšžœžœ ™,—Jšœžœ™Jšœžœ™ Jšœ6Ïc ™CJšžœžœ ™J˜šŸœžœžœ žœ žœžœžœžœ˜IJšœ žœ˜&—J˜š¢œžœžœ˜6šžœ žœžœžœžœ$žœ žœž˜Tšžœžœžœž˜Jšœ žœ˜ Jšœ žœ˜Jšœžœ ˜Jšœ ˜ Jšžœ žœžœžœ˜šžœžœž˜5Jšžœžœžœžœžœžœžœžœ˜J—JšœM˜MJšœ#˜#šœ˜JšœH˜H—šžœžœžœž˜(šžœžœžœž˜$šœžœžœž˜=Jšžœ˜Jšžœ˜—šœ&˜&JšœS˜S—Jšžœ˜—Jšžœ˜—Jšžœ˜—Jšžœ˜—Jš œ˜Jš œ˜—J˜Jšœžœ"žœ žœ˜PJšœžœ"žœ žœ˜RJ˜š¢œžœžœ˜3Jšœžœ ˜Jšœžœ˜šžœžœžœž˜šžœ žœžœžœžœ$žœ žœž˜TJšœžœ ˜Jšœžœ˜Jšœ žœ8˜CJšœ˜šžœ ž˜šžœ˜Jšœ ˜ Jšžœžœ)žœžœ˜9Jšœ žœ#žœžœ˜MJšœžœžœ˜Jšœžœžœ˜—šžœ˜šžœ žœžœž˜:Jšžœžœžœžœ˜)Jšœ$˜$Jšœ5˜5Jšœ;˜;Jš žœžœžœžœžœ˜&—šžœ žœžœ ž˜=Jšžœžœžœžœ˜)Jšœ#˜#Jšœ4˜4JšœR˜RJš žœžœžœžœžœ˜'———šžœžœžœž˜/Jšœžœ*˜JJšœ,˜,Jšœ&˜&Jšœžœ˜(—šžœžœžœž˜/Jšœžœ*˜JJšœf˜fJšœ%˜%Jšœžœ˜(—Jšžœ˜—Jšžœ˜ ——J˜Jšœžœ˜J˜š¢œžœžœ˜2Jšœžœ0˜7Jšœžœ0˜7Jšœžœ"žœ žœ˜Mšžœžœžœž˜5JšœžœO˜YJšœžœ˜šžœžœžœž˜$šžœžœžœž˜!šœžœ#˜,Jšœžœ žœ žœ˜E—Jšœžœžœ ˜&šžœžœ˜JšœQ˜QJšœR˜R—šžœžœ˜JšœQ˜QJšœR˜R—Jšž˜—Jšž˜—Jšžœ˜ J˜J˜—Jš¢W™Wš¢œžœžœ™5šžœ žœžœžœžœ$žœ žœž™TJšœžœ ™Jšœžœ™Jšœ žœ8™CJšœ™šžœžœžœž™5Jšœ>™>šžœžœžœž™$Jšœžœ%™-Jšœžœ6™>JšœžœF™Mšžœžœžœž™!Jšœ žœ™$Jšœ žœ=™Mšžœžœ™Jšœ>™>šžœžœžœž™(Jšœ1žœ™IJšœ*žœ™JJšœ!™!Jšœžœ™%——šžœžœ™Jšœ<™<šžœžœžœž™(Jšœ1žœ™IJšœ*žœ™JJšœB™BJšœ!™!Jšœžœ™%——Jšžœ™—Jšžœ™ ——Jšžœ™—Jšžœ™ ——J˜šŸœžœžœžœžœžœžœ˜JJšœ=˜=Jšœ žœ˜#šžœ>˜DJ˜——Jšœžœžœ ˜š Ÿ œžœžœžœžœžœ˜Dšœ žœ ˜J˜J˜J˜*J˜*—Jšžœ=˜C—šŸœžœžœžœ˜:Jšžœžœ ˜Jšœ žœB˜PJšœ.˜.Jšœ0˜0Jšœ/˜/Jšœ/˜/Jšœ4™4Jšœ4™4—š Ÿ œžœžœžœžœ˜9Jšœ!Ÿ œ'˜Ršžœžœž˜Jšœ žœ˜Jšœ žœ˜Jšžœžœ£˜+——J˜J˜š Ÿœžœžœžœžœžœ˜[Jšžœžœ˜Jšœ%˜%Jšœ,˜,Jšœ ˜ šžœžœžœž˜šžœžœžœž˜$Jšžœžœ ˜šžœ˜Jšœ4žœ žœ ˜Nšœ:˜:Jšžœžœžœžœ˜H—Jšœ˜—š Ÿœžœžœžœ žœ žœ ˜CJšœ£™Jšœžœ ž˜šžœžœ ž˜$Jšžœžœžœžœ˜5—šžœ žœžœž˜Jš œžœžœžœžœ˜EJš œžœžœ žœžœ˜+š žœžœžœžœž˜;Jšžœžœžœžœ˜%šžœžœ£˜,JšœI˜IJšžœžœž œ8˜NJšœžœžœ žœ ˜:Jšžœžœžœžœ˜ ————Jšœžœžœ˜Jš œ žœžœžœ.žœ˜Tšžœžœž˜Jšžœžœ(£˜GJšœžœ˜ Jšœžœ£˜3Jšœžœ£˜2Jšœžœ£˜7Jšœžœ £˜;Jšžœžœ˜—šžœžœ#ž˜2Jšœžœ#žœžœ˜H—J˜šžœ žœ:žœ˜NJšœ˜Jšœ˜—šžœ žœ:žœ˜NJšœ˜Jšœ   œ!˜9—šžœ žœ:žœ˜NJšœ˜Jšœ   œ!˜9—šžœ1žœ˜9Jšœ˜Jšœ   œ.˜F—J˜šžœ žœ4žœ˜HJšœ˜Jšœ ˜ —šžœ žœ3žœ˜GJšœ˜Jšœ& œ˜G—šžœ žœ3žœ˜GJšœ˜Jšœ% œ˜G—šžœ-žœ˜5Jšœ˜Jš œ žœžœžœžœ˜J—Jšžœ˜—Jšžœ˜ ——J˜š Ÿœžœžœžœžœ˜LJšžœžœ˜Jšœ ˜ Jšžœžœ˜)Jšžœžœ/˜IJšžœžœ ˜'Jšžœžœ˜7Jšœ˜Jšœ˜—J˜šŸœžœ žœ žœ ˜/Jšœ8˜8Jšœ Ÿœžœ˜2—J˜šŸœž˜š œžœžœžœžœžœ˜OJšžœ˜—Jšœ žœ?˜KJšœ žœ˜Jšœ žœ˜(Jšœžœžœ˜Jšžœ žœžœ˜#Jšœ*˜*Jšžœžœžœžœ˜0Jšœ7˜7Jšžœ žœžœ ˜ Jšžœ:˜@—J˜šŸœž˜š œ žœžœžœ žœ˜GJšžœ žœžœ˜"—šœ&˜&Jšœžœ˜ Jšžœžœžœ˜%Jšœ<˜<šžœžœžœž˜(Jšžœžœžœžœ˜7Jš žœžœžœ žœž˜2—Jšœžœžœ˜)—JšœJ˜J—J˜Jšœžœžœžœ˜Jšœžœžœ žœ˜%J˜šŸœž˜š œžœžœžœ žœ žœ˜SJšžœžœžœ˜—šœ%˜%Jšžœžœžœžœ˜/Jšœžœ˜&—Jš œ&žœžœžœ žœ ˜WJš žœžœžœžœžœ˜JšœA˜A—J˜š Ÿ œžœžœžœžœžœ˜9Jšžœžœ˜—J˜š Ÿœžœ žœ žœžœžœ ˜IJšœ?˜?Jšœžœžœžœ ˜EJšœžœ ˜&—šŸœžœžœ žœ˜=Jšžœžœ ˜Jšœ žœžœ žœ ˜)Jšœžœ˜Jšœžœ žœ˜Jš œžœžœžœžœžœžœ˜SJš œžœžœžœžœžœžœ˜SJšžœ žœ ˜Jšœ=˜=Jšœ#˜#—š Ÿœžœ$ž œžœžœ ˜YJšžœžœ ˜$JšœK˜KJšœžœžœ˜>Jšœ˜—šŸœžœžœ žœ ˜>Jšœžœ žœ˜4Jšœžœ ˜Jšœ#˜#—J˜š ¢œžœžœ žœžœ ˜BšŸ œ˜&Jšœžœ žœ˜Jšœžœžœ+žœ˜Ešžœžœžœž˜(JšŸœ'˜.Jšœ5žœ˜>——šŸœžœžœžœ˜3Jšœžœ£˜NJšœžœžœžœ&˜:—Jšœžœžœ$˜1Jšœžœžœ˜Jšœ=˜=šžœžœžœž˜šžœ žœžœ˜Jšœ-žœ˜3—šžœžœžœž˜$Jšœ žœ/˜:šžœžœžœž˜!Jšœžœ:˜DJšžœ žœžœ&˜9Jšžœžœžœžœ˜&šžœ!˜#šžœ˜Jšœžœ4˜;Jšœžœ'˜.Jšžœžœžœžœ˜Jšœ4˜4—šžœ˜ Jšœ/˜/Jšœ(žœ˜C——Jšžœ˜—Jšžœ˜—Jšžœ˜—Jšœ(˜(JšœO˜O—J˜š Ÿœžœžœžœ žœžœ™SJšžœžœ ™Jšœ ™ Jšœžœžœ™Dšœ!™!š žœžœ&žœžœž™AJšœ4™4šœ™JšœŸ œ9™Q—šœžœžœ™"Jšœ2žœ™;———Jšœžœžœ™Jšžœ$žœžœžœ™7Jšœ-™-Jšœ"™"Jšœ:™:—J™šŸœžœžœžœ˜>Jšžœžœ ˜Jšœžœžœ˜&šœ!˜!Jšœ˜Jšœžœ˜#Jšœ(˜(Jšœžœ˜—Jšžœ$žœžœžœ˜7Jšœ-˜-JšœŸœžœ ˜k—J˜š Ÿœžœžœžœžœžœ ˜?šžœžœž˜Jšœ žœ žœ ˜&Jšœ žœ £™,Jšžœžœ˜——J˜šŸœžœžœžœ˜@Jšžœžœ˜"Jšžœžœžœžœ˜>Jšœžœžœ˜*Jš žœžœžœžœ#žœ˜L—J˜š Ÿœžœžœ žœžœ˜7Jšœž˜ Jšœžœžœ!˜.Jš žœžœžœ(žœžœžœ˜HJš žœ žœ$žœžœžœžœ˜OJšœžœ ˜JšžœE˜K—J˜š Ÿœžœžœžœžœžœ˜PJšžœžœžœ£,˜Hšžœ žœž˜Jšœ%žœ ˜6Jšœ#žœ˜9Jšžœ žœ(˜A——J˜š Ÿœžœžœžœ žœ˜HJšœžœ;˜BJšœJ˜JJšœ˜Jšœ+žœ˜Išžœžœ˜!Jšœžœ 3œžœ2˜{——J˜š Ÿœžœžœžœ žœ žœ˜`Jšœ žœ˜šžœžœžœž˜4Jšœžœžœ˜1Jš žœ žœžœ*žœžœ˜KJšžœ"žœ"žœ˜Ršžœ*žœžœ+˜^Jšžœž˜ JšžœS˜W—JšœR˜RJšžœ˜ ——J˜šŸœžœžœžœ˜(J˜Sš žœžœž œžœž˜*Jšœžœžœ˜Jšœžœžœ˜˜6Jšžœ ˜ Jšžœ˜Jšžœ˜Jšžœ˜Jšžœ˜—šžœžœžœž˜$Jšžœžœžœžœ˜&Jšœ'˜'Jšœ:˜:Jšžœžœ˜ —šžœžœž˜Jšœ žœ"˜2Jšœ(˜(Jšžœ#˜*—Jšœžœ ˜'Jšžœ˜ ——J˜š Ÿœžœžœžœžœ ˜LJšžœžœžœžœ˜šžœ ž˜Jšœ#žœ˜-šœ#˜#Jšœ%žœ ˜7Jšœ0˜0—˜!Jšœ#žœ ˜5šžœžœžœž˜#Jšœ?žœ˜I——Jšžœ;˜B——J˜šŸœ˜$J™W—J˜Jšœ6˜6J˜J˜Jšžœ˜J˜J˜—…—nú£}