DIRECTORY Basics, CD, CDBasics, CDDirectory, CDProperties, CDRects, CDRoutingObjects, CDSimpleRules, CMosB, Core, CoreClasses, CoreCreate, CoreGeometry, CoreOps, CoreProperties, CoreRoute, 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, CoreRoute, 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 _ 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] = { loc _ CDBasics.SubPoints[loc, CD.InterestBase[obj]]; -- for sb and mux offsets 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; 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] = { 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 _ GetPObjs[val, bit]; node _ CDRoutingObjects.CreateNode[pos, LIST [[key: $SignalName, val: name]]]; 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, November 16, 1987 6:10:33 pm PST 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šœžœžœ*žœ˜Dšžœžœžœž˜(JšŸœ'˜.Jšœ5žœ˜>——šŸœžœžœžœ˜3Jšœžœ£˜NJšœžœžœžœ&˜:—Jšœ#žœ˜8Jšœžœžœ$˜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šœ$žœ˜9Jšœžœžœ˜&šœ!˜!Jšœžœžœ*žœ˜DJšœ˜Jšœžœ˜#Jšœ(žœ"˜NJšœžœ˜—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˜—…—o