DIRECTORY Core, CoreClasses, CoreFlat, CoreOps, HashTable, IO, Mint, Rope, WriteCapa; MintLayoutImpl: CEDAR PROGRAM IMPORTS CoreClasses, CoreFlat, CoreOps, HashTable, IO, Mint, WriteCapa EXPORTS Mint ~ BEGIN OPEN Mint; FlatCellProc: TYPE = PROC [cell: Core.CellType, target: CoreFlat.FlatCellTypeRec _ CoreFlat.allFlatCells, flatCell: CoreFlat.FlatCellTypeRec _ [], instance: CoreClasses.CellInstance _ NIL, parent: Core.CellType _ NIL, flatParent: CoreFlat.FlatCellTypeRec _ [], data: REF ANY _ NIL, wireName: HashTable.Table]; totalSets: CARDINAL _ 0; TypeTable: PUBLIC ARRAY CoreClasses.TransistorType OF TType _ [NEW[TTypeRec _ ["nETran", 20000.0]], NEW[TTypeRec _ ["pETran", 50000.0]], NEW[TTypeRec _ ["nDTran", 20000.0]]]; debug: BOOL _ FALSE; verbose: BOOL _ FALSE; debugCellType: Core.CellType _ NIL; debugCircuit: Circuit _ NIL; debugNode: Node _ NIL; debugNodeList: NodeList _ NIL; CreateCircuit: PROC [rootCell: Core.CellType] RETURNS [circuit: Circuit] ~ { circuit _ NEW[CircuitRec]; circuit.rootCell _ rootCell; circuit.info _ NEW[InfoRec]; circuit.nodeTable _ HashTable.Create[equal: CoreFlat.FlatWireEqual, hash: CoreFlat.FlatWireHash]; }; BuildNode: PUBLIC PROC[flatWire: CoreFlat.FlatWire, circuit: Circuit] RETURNS [Node] = { new: Node; val: HashTable.Value; found: BOOLEAN; [found: found, value: val] _ HashTable.Fetch[circuit.nodeTable, flatWire]; IF found THEN RETURN[NARROW[val]]; new _ NEW[NodeRec]; new.flatWire _ flatWire; IF debug THEN new.watched _ TRUE; -- keeps everything for ever if you debug the cell ... or the program. [] _ HashTable.Store[table: circuit.nodeTable, key: flatWire, value: new]; circuit.info.totalNodes _ circuit.info.totalNodes + 1; new.cap _ WriteCapa.GetRootCap[flatWire.wire]; IF new.cap#0 THEN circuit.info.capNodes _ circuit.info.capNodes + 1; RETURN [new]; }; BuildFet: PROC[gate, ch1, ch2: CoreFlat.FlatWire, type: CoreClasses.TransistorType, l, w: INT, circuit: Circuit] = { fet: Fet; fet _ NEW[FetRec]; fet.type _ type; fet.gate _ BuildNode[gate, circuit]; fet.ch1 _ BuildNode[ch1, circuit]; fet.ch2 _ BuildNode[ch2, circuit]; fet.rOnInv _ w/(l * TypeTable[type].rOn); fet.switch _ FALSE; fet.gate.fetList _ CONS[fet, fet.gate.fetList]; IF fet.ch1 # fet.gate THEN fet.ch1.fetList _ CONS[fet, fet.ch1.fetList]; IF (fet.ch2 # fet.gate) AND (fet.ch2 # fet.ch1) THEN fet.ch2.fetList _ CONS[fet, fet.ch2.fetList]; circuit.info.totalFets[fet.type] _ circuit.info.totalFets[fet.type] + 1; }; BuildNodeList: PUBLIC PROC [name: Rope.ROPE, oldList: NodeList, circuit: Circuit] RETURNS [newList: NodeList] ~ { node: Node _ NodeFromRope[name, circuit]; IF node=NIL THEN RETURN[oldList]; newList _ CONS[node, oldList]; }; NextCellType: PROC [cell: Core.CellType, target: CoreFlat.FlatCellTypeRec, flatCell: CoreFlat.FlatCellTypeRec, instance: CoreClasses.CellInstance, parent: Core.CellType, flatParent: CoreFlat.FlatCellTypeRec, data: REF ANY, wireName: HashTable.Table, proc: FlatCellProc] = { BindCellType: CoreFlat.UnboundFlatCellProc = { BindPublicToActual: CoreOps.EachWirePairProc = { IF publicWire.size=0 THEN { flatWire: CoreFlat.FlatWire _ NARROW[HashTable.Fetch[table: wireName, key: actualWire].value]; [] _ HashTable.Store[table: wireName, key: publicWire, value: flatWire]; }; }; IF CoreOps.VisitBinding[actual: IF instance=NIL OR instance.type#cell THEN previous.public ELSE instance.actual, public: cell.public, eachWirePair: BindPublicToActual] THEN ERROR; proc[cell, target, flatCell, instance, parent, flatParent, data, wireName]; }; previous: Core.CellType _ cell; CoreFlat.NextUnboundCellType[cell, target, flatCell, instance, parent, flatParent, data, BindCellType]; }; Flatten: FlatCellProc = { circuit: Circuit _ NARROW[data]; SELECT cell.class FROM CoreClasses.transistorCellClass => { gateWire: CoreFlat.FlatWire _ NARROW[HashTable.Fetch[table: wireName, key: cell.public[ORD[CoreClasses.TransistorPort.gate]]].value]; ch1Wire: CoreFlat.FlatWire _ NARROW[HashTable.Fetch[table: wireName, key: cell.public[ORD[CoreClasses.TransistorPort.ch1]]].value]; ch2Wire: CoreFlat.FlatWire _ NARROW[HashTable.Fetch[table: wireName, key: cell.public[ORD[CoreClasses.TransistorPort.ch2]]].value]; tran: CoreClasses.Transistor _ NARROW[cell.data]; BuildFet[gateWire, ch1Wire, ch2Wire, tran.type, tran.length, tran.width, circuit]; }; CoreClasses.recordCellClass => { MarkAtomicPublic: PROC[wire: Core.Wire] = { [] _ HashTable.Store[table: publics, key: wire, value: $Public]; }; InsertInternal: PROC[wire: Core.Wire] = { IF NOT HashTable.Fetch[table: publics, key: wire].found THEN { InsertWire[wire, flatCell, circuit, wireName]; }; }; rct: CoreClasses.RecordCellType; publics: HashTable.Table _ HashTable.Create[cell.public.size+1]; rct _ NARROW[cell.data]; CoreOps.VisitRootAtomics[root: cell.public, eachWire: MarkAtomicPublic]; CoreOps.VisitRootAtomics[root: rct.internal, eachWire: InsertInternal]; NextCellType[cell, target, flatCell, instance, parent, flatParent, data, wireName, Flatten] }; ENDCASE => { NextCellType[cell, target, flatCell, instance, parent, flatParent, data, wireName, Flatten] }; }; InsertWire: PROC [wire: Core.Wire, flatCell: CoreFlat.FlatCellTypeRec, circuit: Circuit, wireName: HashTable.Table, wireRoot: CoreFlat.WireRoot _ internal] = { node: Node; flatWire: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec]; flatWire.flatCell _ flatCell; flatWire.wireRoot _ wireRoot; flatWire.wire _ wire; node _ BuildNode[flatWire, circuit]; [] _ HashTable.Store[table: wireName, key: wire, value: flatWire]; }; NetFromCore: PUBLIC PROC[ct: Core.CellType, circuit: Circuit] = { InsertPublic: PROC[wire: Core.Wire] = { InsertWire[wire, CoreFlat.rootCellType, circuit, wireName, public]; }; wireName: HashTable.Table _ HashTable.Create[]; IO.PutF[Mint.StdOut, "\nConverting cell %g . . .", IO.rope[CoreOps.GetCellTypeName[ct]]]; CoreOps.VisitRootAtomics[root: ct.public, eachWire: InsertPublic]; Flatten[cell: ct, data: circuit, wireName: wireName]; IO.PutRope[Mint.StdOut, " \nFinished\n"]; }; Stats: PUBLIC PROC[circuit: Circuit] = { total: INT _ 0; IO.PutF[Mint.StdOut, "\nTotal number of nodes: %d.", IO.int[circuit.info.totalNodes]]; IO.PutF[Mint.StdOut, "\nTotal number of capas: %d.", IO.int[circuit.info.capNodes]]; FOR i: CoreClasses.TransistorType IN CoreClasses.TransistorType DO IF circuit.info.totalFets[i] = 0 THEN LOOP; IO.PutF[Mint.StdOut, "\nNumber of %s transistors: %d.", IO.rope[TypeTable[i].name], IO.int[circuit.info.totalFets[i]]]; total _ total + circuit.info.totalFets[i]; ENDLOOP; IO.PutF[Mint.StdOut, "\nTotal number of transistors: %d.", IO.int[total]]; }; InputData: PUBLIC PROC [ct: Core.CellType, layout: BOOLEAN _ TRUE] RETURNS [circuit: Circuit] ~ { GuessInput: PROC[wire: Core.Wire] = { ropeName: Rope.ROPE _ CoreOps.GetFullWireNames[ct.public, wire].first; flatWire: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec _ [ flatCell: CoreFlat.rootCellType, wire: wire ]]; node: Node _ NARROW[HashTable.Fetch[circuit.nodeTable, flatWire].value]; IF node#VddNode AND node#GndNode THEN { node.input _ TRUE; FOR iFet: FetList _ node.fetList, iFet.rest UNTIL iFet=NIL DO IF iFet.first.ch1=node OR iFet.first.ch2=node THEN { node.input _ FALSE; EXIT; }; ENDLOOP; }; IF node.input THEN IF verbose THEN IO.PutF[Mint.StdOut, "\ninput: %g", IO.rope[ropeName]] ELSE { node.watched _ TRUE; IF verbose THEN IO.PutF[Mint.StdOut, "\n : %g", IO.rope[ropeName]]; }; }; -- GuessInput GndNode, VddNode: Node; circuit _ CreateCircuit[ct]; NetFromCore[ct, circuit]; GndNode _ Mint.NodeFromRope["public.Gnd", circuit]; VddNode _ Mint.NodeFromRope["public.Vdd", circuit]; CoreOps.VisitRootAtomics[root: ct.public, eachWire: GuessInput]; Stats[circuit]; }; NextNodeList: PROC [set: Set, fetList: FetList] RETURNS [nodeList: NodeList _ NIL] ~ { FOR iFetList: FetList _ fetList, iFetList.rest UNTIL iFetList = NIL DO IF NOT iFetList.first.ch1.done THEN { nodeList _ CONS[iFetList.first.ch1, nodeList]; iFetList.first.ch1.done _ TRUE; AddNodeToSet[set, iFetList.first.ch1]; }; IF NOT iFetList.first.ch2.done THEN { nodeList _ CONS[iFetList.first.ch2, nodeList]; iFetList.first.ch2.done _ TRUE; AddNodeToSet[set, iFetList.first.ch2]; }; ENDLOOP; }; --NextNodeList NextFetList: PROC [set: Set, nodeList: NodeList] RETURNS [fetList: FetList _ NIL] ~ { FOR iNodeList: NodeList _ nodeList, iNodeList.rest UNTIL iNodeList = NIL DO FOR iFetList: FetList _ iNodeList.first.fetList, iFetList.rest UNTIL iFetList = NIL DO IF NOT iFetList.first.done THEN IF iFetList.first.gate # iNodeList.first THEN { fetList _ CONS[iFetList.first, fetList]; iFetList.first.done _ TRUE; AddFetToSet[set, iFetList.first]; }; ENDLOOP; ENDLOOP; }; --NextFetList AddNodeToSet: PROC [set: Set, node: Node] ~ { set.lNodes _ CONS[node, set.lNodes]; set.type.nNodes _ set.type.nNodes+1; node.done _ TRUE; }; AddFetToSet: PROC [set: Set, fet: Fet] ~ { set.lFets _ CONS[fet, set.lFets]; fet.done _ TRUE; set.type.nFets[fet.type] _ set.type.nFets[fet.type]+1; }; PrepareSets: PUBLIC PROC [circuit: Circuit, fixedVList: NodeList] ~ { FindOneSet: HashTable.EachPairAction ~ { nodeList: NodeList; fetList: FetList; set: Set; node: Node _ NARROW[value]; IF node.done THEN RETURN; set _ NEW[SetRec]; set.type _ NEW[SetTypeRec]; totalSets _ totalSets+1; nodeList _ LIST[node]; AddNodeToSet[set, node]; UNTIL nodeList = NIL DO fetList _ NextFetList[set, nodeList]; nodeList _ NextNodeList[set, fetList]; ENDLOOP; FindInputs[set]; FindFixedV[set, fixedVList, GndNode, VddNode]; FOR il: Library _ circuit.library, il.rest UNTIL il=NIL DO IF TypeEqual[set.type, il.first.type] THEN { il.first.nElem _ il.first.nElem+1; il.first.setList _ CONS[set, il.first.setList]; set.type _ il.first.type; RETURN; }; ENDLOOP; circuit.library _ CONS[NEW[LibraryElemRec _ [set.type, 1, LIST[set]]], circuit.library]; }; GndNode: Node _ Mint.NodeFromRope["public.Gnd", circuit]; VddNode: Node _ Mint.NodeFromRope["public.Vdd", circuit]; FOR inode: NodeList _ fixedVList, inode.rest UNTIL inode=NIL DO inode.first.done _ TRUE; inode.first.input _ TRUE; ENDLOOP; [] _ HashTable.Pairs[circuit.nodeTable, FindOneSet] }; -- PrepareSets FindInputs: PROC [set: Set] ~ { found: BOOLEAN; FOR ifet: FetList _ set.lFets, ifet.rest UNTIL ifet=NIL DO found _ FALSE; FOR inode: NodeList _ set.lNodes, inode.rest UNTIL inode=NIL DO IF inode.first=ifet.first.gate THEN { found _ TRUE; EXIT; }; ENDLOOP; IF ~found THEN { found _ FALSE; FOR inode: NodeList _ set.inList, inode.rest UNTIL inode=NIL DO IF inode.first=ifet.first.gate THEN { found _ TRUE; EXIT; }; ENDLOOP; IF ~found THEN { set.type.nInput _ set.type.nInput+1; set.inList _ CONS[ifet.first.gate, set.inList]; ifet.first.gate.setList _ CONS[set, ifet.first.gate.setList] }; }; ENDLOOP; }; FindFixedV: PROC [set: Set, fixedVList: NodeList, GndNode, VddNode: Node] ~ { found: BOOLEAN; FOR ifet: FetList _ set.lFets, ifet.rest UNTIL ifet=NIL DO FOR fix: NodeList _ fixedVList, fix.rest UNTIL fix=NIL DO IF ifet.first.ch1=fix.first OR ifet.first.ch2=fix.first THEN { IF fix.first=VddNode THEN set.type.nVddTran _ set.type.nVddTran+1; IF fix.first=GndNode THEN set.type.nGndTran _ set.type.nGndTran+1; found _ FALSE; FOR inode: NodeList _ set.fixedV, inode.rest UNTIL inode=NIL DO IF inode.first=fix.first THEN { found _ TRUE; EXIT; }; ENDLOOP; IF ~found THEN set.fixedV _ CONS[fix.first, set.fixedV]; }; ENDLOOP; ENDLOOP; }; TypeEqual: PROC [s1, s2: SetType] RETURNS [ok: BOOLEAN _ FALSE] ~ { FOR tt: CoreClasses.TransistorType IN CoreClasses.TransistorType DO IF s1.nFets[tt]#s2.nFets[tt] THEN RETURN; ENDLOOP; IF s1.nVddTran#s2.nVddTran THEN RETURN; IF s1.nGndTran#s2.nGndTran THEN RETURN; IF s1.nNodes#s2.nNodes THEN RETURN; IF s1.nInput#s2.nInput THEN RETURN; ok _ TRUE; }; PrintSetType: PROC [out: IO.STREAM, setType: SetType] ~ { IO.PutF[out, " %4d, %4d,", IO.int[setType.nFets[nE]], IO.int[setType.nFets[pE]]]; IO.PutF[out, " %4d, %4d, %4d, %4d", IO.int[setType.nVddTran], IO.int[setType.nGndTran], IO.int[setType.nNodes], IO.int[setType.nInput]]; }; SolveInverter: PROC [set: Set, t: ps] RETURNS [tlast: ps] ~ { out: Node ~ set.lNodes.first; in: Node ~ set.inList.first; }; ErrMsg: PROC [nodeList: NodeList, msg: Rope.ROPE, circuit: Circuit] ~ { IO.PutF[Mint.StdOut, "\n%g:", IO.rope[msg]]; FOR iNodeList: NodeList _ nodeList, iNodeList.rest UNTIL iNodeList=NIL DO IO.PutF[Mint.StdOut, "\n%g", IO.rope[Mint.RopeFromNode[iNodeList.first, circuit]]]; ENDLOOP; IO.PutF[Mint.StdOut, "\n" ]; }; CheckLibrary: PUBLIC PROC [circuit: Circuit] ~ { n: NAT _ 0; FOR il: Library _ circuit.library, il.rest UNTIL il=NIL DO SELECT TRUE FROM il.first.type.nFets[nE]+il.first.type.nFets[pE]=0 => FOR iSetList: SetList _ il.first.setList, iSetList.rest UNTIL iSetList=NIL DO IF iSetList.first.lNodes.first.flatWire.wireRoot#public THEN { IF iSetList.first.lNodes.first.setList=NIL THEN ErrMsg[iSetList.first.lNodes, "These Nodes are isolated", circuit] ELSE ErrMsg[iSetList.first.lNodes, "These Nodes are not loaded by any fet", circuit]}; ENDLOOP; il.first.type.nVddTran=0 => FOR iSetList: SetList _ il.first.setList, iSetList.rest UNTIL iSetList=NIL DO ErrMsg[iSetList.first.lNodes, "These Nodes have no path to Vdd", circuit]; ENDLOOP; il.first.type.nGndTran=0 => FOR iSetList: SetList _ il.first.setList, iSetList.rest UNTIL iSetList=NIL DO ErrMsg[iSetList.first.lNodes, "These Nodes have no path to Gnd", circuit]; ENDLOOP; ENDCASE; ENDLOOP; }; OutputResults: PUBLIC PROC [circuit: Circuit] ~ { n: NAT _ 0; IO.PutF[Mint.StdOut, "\n nE pE ^Vdd ^Gnd nodes inputs"]; FOR il: Library _ circuit.library, il.rest UNTIL il=NIL DO IO.PutF[Mint.StdOut, "\n%5d el: %5d Type: ", IO.int[n], IO.int[il.first.nElem]]; PrintSetType[Mint.StdOut, il.first.type]; n _ n+1; ENDLOOP; }; IO.PutRope[Mint.StdOut, "\nMintLayout\n"]; END. €MintLayoutImpl.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Christian LeCocq December 17, 1986 11:43:16 am PST Bertrand Serlet October 18, 1986 8:12:25 pm PDT some usefull definitions Basic data stuctures builders This procedure sees if a given node exists, and makes a new one if necessary. A pointer is returned to the new or existing node. This procedure builds a transistor data structure and links it into the network under construction. cap: REAL; Input From Core PROC [actualWire, publicWire: Wire] Circuit Preparation PROC [key: Key, value: Value] RETURNS [quit: BOOLEAN _ FALSE]; ... to be finished. Κ‰˜šœ™Icodešœ Οmœ1™Jšœ.˜.J˜—Jšœ˜J˜—Jšœ ˜ Jšœ@˜@Jšœžœ ˜JšœH˜HJšœG˜GKšœ[˜[J˜—šžœ˜ Kšœ[˜[Jšœ˜——Jšœ˜J˜—š  œžœ˜ŸJšœ ˜ Jšœžœ˜8Jšœ˜Jšœ˜Jšœ˜Jšœ$˜$JšœB˜BJšœ˜J˜—š  œžœžœ)˜AJ˜š  œžœ˜'JšœC˜CJšœ˜J˜—J˜/Jšžœ1žœ$˜YJšœB˜BJšœ5˜5Jšžœ'˜)J˜J˜——™š œžœžœ˜(Jšœžœ˜Jšžœ3žœ˜VJšžœ3žœ˜Tšžœžœž˜BJšžœžœžœ˜+Jšžœ6žœžœ!˜wJšœ*˜*Jšžœ˜—Jšžœ9žœ ˜JJ˜J˜—š   œžœžœžœžœžœ˜aš  œžœ˜%Kšœžœ3˜Fšœžœ˜:Jšœ ˜ Jšœ ˜ Jšœ˜—Jšœ žœ5˜Hšžœžœžœ˜'Kšœ žœ˜šžœ)žœžœž˜=šžœžœžœžœžœžœžœ˜4Kšœ žœ˜Kšžœ˜K˜—Kšžœ˜—K˜—š žœ žœžœ žœžœ"žœ˜YKšžœ˜Kšœžœ˜Kšžœ žœžœ#žœ˜HK˜—Kšœ‘˜K˜—Kšœ˜Kšœ˜Kšœ˜Kšœ3˜3Kšœ3˜3Kšœ@˜@K˜˜K˜——š  œžœžœžœ˜Všžœ,žœ žœž˜Fšžœžœžœ˜%Kšœ žœ˜.Kšœžœ˜Kšœ&˜&K˜—šžœžœžœ˜%Kšœ žœ˜.Kšœžœ˜Kšœ&˜&K˜—Kšžœ˜—Kšœ‘˜K˜—š  œžœ žœžœ˜Ušžœ0žœ žœž˜Kšžœ<žœ žœž˜Všžœžœžœ˜ šžœ'žœ˜/Kšœ žœ˜(Kšœžœ˜Kšœ!˜!K˜——Kšžœ˜—Kšžœ˜—Kšœ‘ ˜K˜—š  œžœ˜-Kšœ žœ˜$Kšœ$˜$Kšœ ž˜˜K˜——š  œžœ˜*Kšœ žœ˜!Kšœ ž˜Kšœ6˜6˜K˜K˜——š  œž œ-˜EK˜š  œ˜(Kšžœžœžœžœ™>Kšœ˜Kšœ˜K˜ Kšœ žœ˜Kšžœ žœžœ˜Kšœžœ ˜Kšœ žœ ˜K˜Kšœ žœ˜Kšœ˜šžœ žœž˜Kšœ%˜%Kšœ&˜&Kšžœ˜—Kšœ˜Kšœ.˜.šžœ(žœžœž˜:šžœ#žœ˜,K˜"Kšœžœ˜/Kšœ˜Kšžœ˜K˜—Kšžœ˜—Kšœžœžœ žœ˜XK˜K˜—Kšœ9˜9Kšœ9˜9šžœ*žœžœž˜?Kšœžœ˜Kšœžœ˜Kšžœ˜—Kšœ3˜3Kšœ‘˜K˜—š  œžœ˜Kšœžœ˜šžœ&žœžœž˜:Kšœžœ˜šžœ*žœžœž˜?šžœžœ˜%Kšœžœ˜ Kšžœ˜K˜—Kšžœ˜—šžœžœ˜Kšœžœ˜šžœ*žœžœž˜?šžœžœ˜%Kšœžœ˜ Kšžœ˜K˜—Kšžœ˜—šžœžœ˜Kšœ$˜$Kšœ žœ˜/Kšœžœ˜Kšžœžœ)˜BKšžœžœ)˜BKšœžœ˜šžœ*žœžœž˜?šžœžœ˜Kšœžœ˜ Kšžœ˜K˜—Kšžœ˜—Kšžœžœžœ˜8K˜—Kšžœ˜—Kšžœ˜—K˜K˜—š ’ œžœžœžœžœ˜Cšžœ žœž˜CKšžœžœžœ˜)Kšžœ˜—Kšžœžœžœ˜'Kšžœžœžœ˜'Kšžœžœžœ˜#Kšžœžœžœ˜#Kšœžœ˜ K˜K˜—š  œžœžœžœ˜:Kšžœžœžœ˜QKš žœ"žœžœžœžœ˜ˆK˜K˜—š  œžœžœ˜=K˜Kšœ˜K™K˜K˜—š œžœ žœ˜GK˜,šžœ0žœ žœž˜IKšœS˜SKšžœ˜—K˜K˜K˜—š  œž œ˜0Kšœžœ˜ šžœ(žœžœž˜:šžœžœž˜šœ5žœ5žœ žœž˜‚šžœ6žœ˜>Kšžœ%žœžœDžœR˜Ι—Kšžœ˜—šœžœ5žœ žœž˜iKšœJ˜JKšžœ˜—šœžœ5žœ žœž˜iKšœJ˜JKšžœ˜—Kšžœ˜—Kšžœ˜—K˜K˜—š  œž œ˜1Kšœžœ˜ KšžœT˜Všžœ(žœžœž˜:Kšžœ.žœ žœ˜SKšœ)˜)K˜Kšžœ˜—K˜K˜—Jšžœ(˜*—Jšžœ˜—…—5΄G½