DIRECTORY CD, CDCells, CDMenus, CDOps, CDSequencer, Core, CoreClasses, CoreCreate, CoreDirectory, CoreFlat, CoreOps, CoreProperties, HashTable, IO, Logic, Ports, PW, PWCore, Rosemary, RosemaryUser, Sinix, Sisyph, TerminalIO; LogicImpl: CEDAR PROGRAM IMPORTS CDCells, CDMenus, CDOps, CoreClasses, CoreCreate, CoreDirectory, CoreOps, CoreProperties, HashTable, IO, Ports, PW, Rosemary, RosemaryUser, Sinix, Sisyph, TerminalIO EXPORTS Logic = BEGIN OPEN Logic, CoreCreate; libCellClass: PUBLIC Core.CellClass _ CoreOps.SetClassPrintProc[NEW [Core.CellClassRec _ [name: "LibCell", recast: RecastLibCell]], PrintLibCell]; CreateLibCell: PUBLIC PROC [public: Wire, ctName, libName, name: ROPE _ NIL, props: Properties _ NIL] RETURNS [ct: CellType] = { ct _ CoreOps.CreateCellType[ class: libCellClass, public: public, data: NEW[LibCellRec _ [libName, ctName]], name: name, props: props]; }; RecastLibCell: Core.RecastProc = { -- check public!!!! scRef: LibCellRef _ NARROW [me.data]; lib: CoreDirectory.Library _ CoreDirectory.FetchLibrary[scRef.libName]; schCell: CellType _ CoreDirectory.Fetch[library: lib, key: scRef.ctName]; IF schCell=NIL THEN {TerminalIO.WriteF["CellType %g not in library %g", IO.rope[scRef.ctName], IO.rope[scRef.libName]]; ERROR}; -- maybe a signal ? new _ CoreClasses.CreatePermutedRecordCell[iconPublic: me.public, schCell: schCell, table: CreateIdentityTable[me.public, schCell.public]] }; CreateIdentityTable: PROC [iconPublic, schPublic: Wire] RETURNS [table: HashTable.Table] ~ { FindWire: PROC [iconPublic: Wire, name: ROPE] RETURNS [iconWire: Wire _ NIL] ~ { n: INT _ CoreOps.GetWireIndex[iconPublic, name]; IF n>=0 THEN RETURN[iconPublic[n]]; }; AddInTable: CoreOps.EachWireProc ~ { name: ROPE _ CoreOps.GetShortWireName[wire]; iconWire: Wire; IF name=NIL THEN RETURN; iconWire _ FindWire[iconPublic, name]; IF iconWire=NIL THEN RETURN; [] _ HashTable.Store[table, wire, iconWire]; }; table _ HashTable.Create[]; [] _ CoreOps.VisitWire[schPublic, AddInTable]; }; PrintLibCell: CoreOps.PrintClassProc = { scRef: LibCellRef _ NARROW [data]; CoreOps.PrintIndent[indent, out]; out.PutF["Cell '%g' from library '%g'\n", IO.rope[scRef.ctName], IO.rope[scRef.libName]]; }; logicCutSet: PUBLIC ROPE _ "Logic"; macroCutSet: PUBLIC ROPE _ "LogicMacro"; defaultLibName: ROPE = "CMOSB"; schDesignName: ROPE = "Logic"; schDesign: CD.Design _ PW.OpenDesign[schDesignName]; cx: PUBLIC Sisyph.Context _ Sisyph.Create[schDesign]; MakeSC: PROC [nameInLib, name: ROPE, public: Wire] RETURNS [ct: CellType] ~ { ct _ CreateLibCell[name: name, public: public, ctName: nameInLib, libName: defaultLibName]; -- a global ct _ Rosemary.BindCellType[ct, name]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: logicCutSet]; }; InitPorts: PUBLIC PROC [ct: CellType, initType: Ports.PortType _ l, initDrive: Ports.Drive _ none, n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10: ROPE _ NIL] = { InitP: PROC [ct: CellType, initType: Ports.PortType, initDrive: Ports.Drive, n: ROPE] ~ { [] _ Ports.InitPort[CoreOps.FindWire[ct.public, n], initType, initDrive]; }; IF n0#NIL THEN InitP[ct, initType, initDrive, n0] ELSE RETURN; IF n1#NIL THEN InitP[ct, initType, initDrive, n1] ELSE RETURN; IF n2#NIL THEN InitP[ct, initType, initDrive, n2] ELSE RETURN; IF n3#NIL THEN InitP[ct, initType, initDrive, n3] ELSE RETURN; IF n4#NIL THEN InitP[ct, initType, initDrive, n4] ELSE RETURN; IF n5#NIL THEN InitP[ct, initType, initDrive, n5] ELSE RETURN; IF n6#NIL THEN InitP[ct, initType, initDrive, n6] ELSE RETURN; IF n7#NIL THEN InitP[ct, initType, initDrive, n7] ELSE RETURN; IF n8#NIL THEN InitP[ct, initType, initDrive, n8] ELSE RETURN; IF n9#NIL THEN InitP[ct, initType, initDrive, n9] ELSE RETURN; IF n10#NIL THEN InitP[ct, initType, initDrive, n10] ELSE RETURN; }; PortIndexes: PUBLIC PROC [wire: Wire, n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11: ROPE _ NIL] RETURNS [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11: NAT _ LAST[NAT]] ~ { IF n0#NIL THEN i0 _ Ports.PortIndex[wire, n0] ELSE RETURN; IF n1#NIL THEN i1 _ Ports.PortIndex[wire, n1] ELSE RETURN; IF n2#NIL THEN i2 _ Ports.PortIndex[wire, n2] ELSE RETURN; IF n3#NIL THEN i3 _ Ports.PortIndex[wire, n3] ELSE RETURN; IF n4#NIL THEN i4 _ Ports.PortIndex[wire, n4] ELSE RETURN; IF n5#NIL THEN i5 _ Ports.PortIndex[wire, n5] ELSE RETURN; IF n6#NIL THEN i6 _ Ports.PortIndex[wire, n6] ELSE RETURN; IF n7#NIL THEN i7 _ Ports.PortIndex[wire, n7] ELSE RETURN; IF n8#NIL THEN i8 _ Ports.PortIndex[wire, n8] ELSE RETURN; IF n9#NIL THEN i9 _ Ports.PortIndex[wire, n9] ELSE RETURN; IF n10#NIL THEN i10 _ Ports.PortIndex[wire, n10] ELSE RETURN; IF n11#NIL THEN i11 _ Ports.PortIndex[wire, n11] ELSE RETURN; }; NotL: PUBLIC PROC [a: Ports.Level] RETURNS [b: Ports.Level] ~ { b_ SELECT a FROM L => H, H => L, ENDCASE => X}; SumL: PUBLIC PROC [a, b, c: Ports.Level] RETURNS [carry, s: Ports.Level] ~ { IF a=X OR b=X OR c=X THEN RETURN[X, X]; carry _ IF (a=H AND b=H) OR (b=H AND c=H) OR (c=H AND a=H) THEN H ELSE L; s _ IF (a=H AND b=H AND c=L) OR (b=H AND c=H AND a=L) OR (c=H AND a=H AND b=L) OR (a=L AND b=L AND c=L) THEN L ELSE H; }; CopyLS: PUBLIC PROC [from, to: Ports.LevelSequence] ~ { FOR i: NAT IN [0..from.size) DO to[i] _ from[i]; ENDLOOP; }; SetLS: PUBLIC PROC [seq: Ports.LevelSequence, level: Ports.Level] ~ { FOR i: NAT IN [0..seq.size) DO seq[i] _ level; ENDLOOP; }; VddName: ROPE = Rosemary.Register[roseClassName: "Vdd", evalSimple: VddSimple]; GndName: ROPE = Rosemary.Register[roseClassName: "Gnd", evalSimple: GndSimple]; vdd, gnd: NAT; Vdd: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "vdd", name: VddName, public: Wires["Vdd"]]; [vdd] _ PortIndexes[ct.public, "Vdd"]; [] _ InitPorts[ct, l, drive, "Vdd"]; }; VddSimple: Rosemary.EvalProc = {p[vdd].l _ H}; Gnd: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "gnd", name: GndName, public: Wires["Gnd"]]; [gnd] _ PortIndexes[ct.public, "Gnd"]; [] _ InitPorts[ct, l, drive, "Gnd"]; }; GndSimple: Rosemary.EvalProc = {p[gnd].l _ L}; InvName: ROPE = Rosemary.Register[roseClassName: "Inv", evalSimple: InvSimple]; invVdd, invGnd, invIn, invOut: NAT; Inv: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "inv", name: InvName, public: Wires["Vdd", "Gnd", "I", "X"]]; [invVdd, invGnd, invIn, invOut] _ PortIndexes[ct.public, "Vdd", "Gnd", "I", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I"]; [] _ InitPorts[ct, l, drive, "X"]; }; Buffer: PUBLIC PROC[d: NAT] RETURNS [ct: CellType] = { ct _ Inv[]; -- good enough for now!!!! }; InvSimple: Rosemary.EvalProc = { p[invOut].l _ SELECT p[invIn].l FROM L => H, H => L, ENDCASE => X }; TstDriverName: ROPE = Rosemary.Register[roseClassName: "TstDriver", evalSimple: TstDriverSimple]; tstDriverVdd, tstDriverGnd, tstDriverIn, tstDriverOut, tstDriverEN, tstDriverNEN: NAT; TstDriver: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "tstDriver", name: TstDriverName, public: Wires["Vdd", "Gnd", "I", "X", "EN", "NEN"]]; [tstDriverVdd, tstDriverGnd, tstDriverIn, tstDriverOut] _ PortIndexes[ct.public, "Vdd", "Gnd", "I", "X", "EN", "NEN"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I", "EN", "NEN", "X"]; }; TstDriverSimple: Rosemary.EvalProc = { IF p[tstDriverEN].l#NotL[p[tstDriverNEN].l] THEN { p[tstDriverOut].d _ drive; p[tstDriverOut].l _ X; RETURN}; SELECT p[tstDriverEN].l FROM H => {p[tstDriverOut].l _ NotL[p[tstDriverIn].l]; p[tstDriverOut].d _ drive}; L => {p[tstDriverOut].d _ none}; ENDCASE => {p[tstDriverOut].l _ X; p[tstDriverOut].d _ drive}; }; AndName: ROPE = Rosemary.Register[roseClassName: "And", evalSimple: AndSimple]; And2Name: ROPE = Rosemary.Register[roseClassName: "And2", evalSimple: And2Simple]; And3Name: ROPE = Rosemary.Register[roseClassName: "And3", evalSimple: And3Simple]; And4Name: ROPE = Rosemary.Register[roseClassName: "And4", evalSimple: And4Simple]; andVdd, andGnd, andIn, andOut: NAT; and2Vdd, and2Gnd, and2InA, and2InB, and2Out: NAT; and3Vdd, and3Gnd, and3InA, and3InB, and3InC, and3Out: NAT; and4Vdd, and4Gnd, and4InA, and4InB, and4InC, and4InD, and4Out: NAT; And: PUBLIC PROC[n: NAT] RETURNS [ct: CellType] = { IF n<2 THEN ERROR; -- improve ct _ CoreClasses.CreateUnspecified[name: AndName, public: Wires["Vdd", "Gnd", Seq["I", n], "X"]]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: AndName]; [andVdd, andGnd, andIn, andOut] _ PortIndexes[ct.public, "Vdd", "Gnd", "I", "X"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: macroCutSet]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd"]; [] _ InitPorts[ct, ls, none, "I"]; [] _ InitPorts[ct, l, drive, "X"]; }; AndSimple: Rosemary.EvalProc = { allHigh: BOOL _ TRUE; FOR i: NAT IN [0..p[andIn].ls.size) DO IF p[andIn].ls[i]=L THEN {p[andOut].l _ L; RETURN}; allHigh _ allHigh AND p[andIn].ls[i]=H; ENDLOOP; p[andOut].l _ SELECT TRUE FROM allHigh => H, ENDCASE => X; }; And2: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "and2", name: And2Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "X"]]; [and2Vdd, and2Gnd, and2InA, and2InB, and2Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B"]; [] _ InitPorts[ct, l, drive, "X"]; }; And2Simple: Rosemary.EvalProc = { p[and2Out].l _ SELECT TRUE FROM p[and2InA].l=L OR p[and2InB].l=L => L, p[and2InA].l=H AND p[and2InB].l=H => H, ENDCASE => X; }; And3: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "and3", name: And3Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "I-C", "X"]]; [and3Vdd, and3Gnd, and3InA, and3InB, and3InC, and3Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B", "I-C"]; [] _ InitPorts[ct, l, drive, "X"]; }; And3Simple: Rosemary.EvalProc = { p[and3Out].l _ SELECT TRUE FROM p[and3InA].l=L OR p[and3InB].l=L OR p[and3InC].l=L => L, p[and3InA].l=H AND p[and3InB].l=H AND p[and3InC].l=H => H, ENDCASE => X; }; And4: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "and4", name: And4Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D", "X"]]; [and4Vdd, and4Gnd, and4InA, and4InB, and4InC, and4InD, and4Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D"]; [] _ InitPorts[ct, l, drive, "X"]; }; And4Simple: Rosemary.EvalProc = { p[and4Out].l _ SELECT TRUE FROM p[and4InA].l=L OR p[and4InB].l=L OR p[and4InC].l=L OR p[and4InD].l=L => L, p[and4InA].l=H AND p[and4InB].l=H AND p[and4InC].l=H AND p[and4InD].l=H => H, ENDCASE => X; }; NandName: ROPE = Rosemary.Register[roseClassName: "Nand", evalSimple: AndSimple]; Nand2Name: ROPE = Rosemary.Register[roseClassName: "Nand2", evalSimple: Nand2Simple]; Nand3Name: ROPE = Rosemary.Register[roseClassName: "Nand3", evalSimple: Nand3Simple]; Nand4Name: ROPE = Rosemary.Register[roseClassName: "Nand4", evalSimple: Nand4Simple]; nandVdd, nandGnd, nandIn, nandOut: NAT; nand2Vdd, nand2Gnd, nand2InA, nand2InB, nand2Out: NAT; nand3Vdd, nand3Gnd, nand3InA, nand3InB, nand3InC, nand3Out: NAT; nand4Vdd, nand4Gnd, nand4InA, nand4InB, nand4InC, nand4InD, nand4Out: NAT; Nand: PUBLIC PROC[n: NAT] RETURNS [ct: CellType] = { IF n<2 THEN ERROR; -- improve ct _ CoreClasses.CreateUnspecified[name: NandName, public: Wires["Vdd", "Gnd", Seq["I", n], "X"]]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: NandName]; [nandVdd, nandGnd, nandIn, nandOut] _ PortIndexes[ct.public, "Vdd", "Gnd", "I", "X"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: macroCutSet]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd"]; [] _ InitPorts[ct, ls, none, "I"]; [] _ InitPorts[ct, l, drive, "X"]; }; NandSimple: Rosemary.EvalProc = { allHigh: BOOL _ TRUE; FOR i: NAT IN [0..p[nandIn].ls.size) DO IF p[nandIn].ls[i]=L THEN {p[nandOut].l _ H; RETURN}; allHigh _ allHigh AND p[nandIn].ls[i]=H; ENDLOOP; p[nandOut].l _ SELECT TRUE FROM allHigh => L, ENDCASE => X; }; Nand2: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "nand2", name: Nand2Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "X"]]; [nand2Vdd, nand2Gnd, nand2InA, nand2InB, nand2Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B"]; [] _ InitPorts[ct, l, drive, "X"]; }; Nand2Simple: Rosemary.EvalProc = { p[nand2Out].l _ SELECT TRUE FROM p[nand2InA].l=L OR p[nand2InB].l=L => H, p[nand2InA].l=H AND p[nand2InB].l=H => L, ENDCASE => X; }; Nand3: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "nand3", name: Nand3Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "I-C", "X"]]; [nand3Vdd, nand3Gnd, nand3InA, nand3InB, nand3InC, nand3Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B", "I-C"]; [] _ InitPorts[ct, l, drive, "X"]; }; Nand3Simple: Rosemary.EvalProc = { p[nand3Out].l _ SELECT TRUE FROM p[nand3InA].l=L OR p[nand3InB].l=L OR p[nand3InC].l=L => H, p[nand2InA].l=H AND p[nand2InB].l=H AND p[nand3InC].l=H => L, ENDCASE => X; }; Nand4: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "nand4", name: Nand4Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D", "X"]]; [nand4Vdd, nand4Gnd, nand4InA, nand4InB, nand4InC, nand4InD, nand4Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D"]; [] _ InitPorts[ct, l, drive, "X"]; }; Nand4Simple: Rosemary.EvalProc = { p[nand4Out].l _ SELECT TRUE FROM p[nand4InA].l=L OR p[nand4InB].l=L OR p[nand4InC].l=L OR p[nand4InD].l=L => H, p[nand4InA].l=H AND p[nand4InB].l=H AND p[nand4InC].l=H AND p[nand4InD].l=H => L, ENDCASE => X; }; OrName: ROPE = Rosemary.Register[roseClassName: "Or", evalSimple: OrSimple]; Or2Name: ROPE = Rosemary.Register[roseClassName: "Or2", evalSimple: Or2Simple]; Or3Name: ROPE = Rosemary.Register[roseClassName: "Or3", evalSimple: Or3Simple]; Or4Name: ROPE = Rosemary.Register[roseClassName: "Or4", evalSimple: Or4Simple]; orVdd, orGnd, orIn, orOut: NAT; or2Vdd, or2Gnd, or2InA, or2InB, or2Out: NAT; or3Vdd, or3Gnd, or3InA, or3InB, or3InC, or3Out: NAT; or4Vdd, or4Gnd, or4InA, or4InB, or4InC, or4InD, or4Out: NAT; Or: PUBLIC PROC[n: NAT] RETURNS [ct: CellType] = { IF n<2 THEN ERROR; -- improve ct _ CoreClasses.CreateUnspecified[name: OrName, public: Wires["Vdd", "Gnd", Seq["I", n], "X"]]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: OrName]; [orVdd, orGnd, orIn, orOut] _ PortIndexes[ct.public, "Vdd", "Gnd", "I", "X"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: macroCutSet]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd"]; [] _ InitPorts[ct, ls, none, "I"]; [] _ InitPorts[ct, l, drive, "X"]; }; OrSimple: Rosemary.EvalProc = { allLow: BOOL _ TRUE; FOR i: NAT IN [0..p[orIn].ls.size) DO IF p[orIn].ls[i]=H THEN {p[orOut].l _ H; RETURN}; allLow _ allLow AND p[orIn].ls[i]=L; ENDLOOP; p[orOut].l _ SELECT TRUE FROM allLow => L, ENDCASE => X; }; Or2: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "or2", name: Or2Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "X"]]; [or2Vdd, or2Gnd, or2InA, or2InB, or2Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B"]; [] _ InitPorts[ct, l, drive, "X"]; }; Or2Simple: Rosemary.EvalProc = { -- same proc for both p[or2Out].l _ SELECT TRUE FROM p[or2InA].l=H OR p[or2InB].l=H => H, p[or2InA].l=L AND p[or2InB].l=L => L, ENDCASE => X; }; Or3: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "or3", name: Or3Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "I-C", "X"]]; [or3Vdd, or3Gnd, or3InA, or3InB, or3InC, or3Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B", "I-C"]; [] _ InitPorts[ct, l, drive, "X"]; }; Or3Simple: Rosemary.EvalProc = { -- same proc for both p[or3Out].l _ SELECT TRUE FROM p[or3InA].l=H OR p[or3InB].l=H OR p[or3InC].l=H => H, p[or3InA].l=L AND p[or3InB].l=L AND p[or3InC].l=L => L, ENDCASE => X; }; Or4: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "or4", name: Or4Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D", "X"]]; [or4Vdd, or4Gnd, or4InA, or4InB, or4InC, or4InD, or4Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D"]; [] _ InitPorts[ct, l, drive, "X"]; }; Or4Simple: Rosemary.EvalProc = { -- same proc for both p[or4Out].l _ SELECT TRUE FROM p[or4InA].l=H OR p[or4InB].l=H OR p[or4InC].l=H OR p[or4InD].l=H => H, p[or4InA].l=L AND p[or4InB].l=L AND p[or4InC].l=L AND p[or4InD].l=L => L, ENDCASE => X; }; NorName: ROPE = Rosemary.Register[roseClassName: "Nor", evalSimple: NorSimple]; Nor2Name: ROPE = Rosemary.Register[roseClassName: "Nor2", evalSimple: Nor2Simple]; Nor3Name: ROPE = Rosemary.Register[roseClassName: "Nor3", evalSimple: Nor3Simple]; Nor4Name: ROPE = Rosemary.Register[roseClassName: "Nor4", evalSimple: Nor4Simple]; norVdd, norGnd, norIn, norOut: NAT; nor2Vdd, nor2Gnd, nor2InA, nor2InB, nor2Out: NAT; nor3Vdd, nor3Gnd, nor3InA, nor3InB, nor3InC, nor3Out: NAT; nor4Vdd, nor4Gnd, nor4InA, nor4InB, nor4InC, nor4InD, nor4Out: NAT; Nor: PUBLIC PROC[n: NAT] RETURNS [ct: CellType] = { IF n<2 THEN ERROR; -- improve ct _ CoreClasses.CreateUnspecified[name: NorName, public: Wires["Vdd", "Gnd", Seq["I", n], "X"]]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: NorName]; [norVdd, norGnd, norIn, norOut] _ PortIndexes[ct.public, "Vdd", "Gnd", "I", "X"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: macroCutSet]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd"]; [] _ InitPorts[ct, ls, none, "I"]; [] _ InitPorts[ct, l, drive, "X"]; }; NorSimple: Rosemary.EvalProc = { allLow: BOOL _ TRUE; FOR i: NAT IN [0..p[norIn].ls.size) DO IF p[norIn].ls[i]=H THEN {p[norOut].l _ L; RETURN}; allLow _ allLow AND p[norIn].ls[i]=L; ENDLOOP; p[norOut].l _ SELECT TRUE FROM allLow => H, ENDCASE => X; }; Nor2: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "nor2", name: Nor2Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "X"]]; [nor2Vdd, nor2Gnd, nor2InA, nor2InB, nor2Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B"]; [] _ InitPorts[ct, l, drive, "X"]; }; Nor2Simple: Rosemary.EvalProc = { -- same proc for both p[nor2Out].l _ SELECT TRUE FROM p[nor2InA].l=H OR p[nor2InB].l=H => L, p[nor2InA].l=L AND p[nor2InB].l=L => H, ENDCASE => X; }; Nor3: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "nor3", name: Nor3Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "I-C", "X"]]; [nor3Vdd, nor3Gnd, nor3InA, nor3InB, nor3InC, nor3Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B", "I-C"]; [] _ InitPorts[ct, l, drive, "X"]; }; Nor3Simple: Rosemary.EvalProc = { -- same proc for both p[nor3Out].l _ SELECT TRUE FROM p[nor3InA].l=H OR p[nor3InB].l=H OR p[nor3InC].l=H => L, p[nor3InA].l=L AND p[nor3InB].l=L AND p[nor3InC].l=L => H, ENDCASE => X; }; Nor4: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "nor4", name: Nor4Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D", "X"]]; [nor4Vdd, nor4Gnd, nor4InA, nor4InB, nor4InC, nor4InD, nor4Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D"]; [] _ InitPorts[ct, l, drive, "X"]; }; Nor4Simple: Rosemary.EvalProc = { -- same proc for both p[nor4Out].l _ SELECT TRUE FROM p[nor4InA].l=H OR p[nor4InB].l=H OR p[nor4InC].l=H OR p[nor4InD].l=H => L, p[nor4InA].l=L AND p[nor4InB].l=L AND p[nor4InC].l=L AND p[nor4InD].l=L => H, ENDCASE => X; }; Xor2Name: ROPE = Rosemary.Register[roseClassName: "Xor2", evalSimple: Xor2Simple]; Xnor2Name: ROPE = Rosemary.Register[roseClassName: "Xnor2", evalSimple: Xnor2Simple]; xor2Vdd, xor2Gnd, xor2InA, xor2InB, xor2Out: NAT; xnor2Vdd, xnor2Gnd, xnor2InA, xnor2InB, xnor2Out: NAT; Xor2: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "xor2", name: Xor2Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "X"]]; [xor2Vdd, xor2Gnd, xor2InA, xor2InB, xor2Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B"]; [] _ InitPorts[ct, l, drive, "X"]; }; Xor2Simple: Rosemary.EvalProc = { p[xor2Out].l _ SELECT TRUE FROM p[xor2InA].l=X OR p[xor2InB].l=X => X, (p[xor2InA].l=H AND p[xor2InB].l=H) OR (p[xor2InA].l=L AND p[xor2InB].l=L) => L, ENDCASE => H; }; Xnor2: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "xnor2", name: Xnor2Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "X"]]; [xnor2Vdd, xnor2Gnd, xnor2InA, xnor2InB, xnor2Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B"]; [] _ InitPorts[ct, l, drive, "X"]; }; Xnor2Simple: Rosemary.EvalProc = { p[xnor2Out].l _ SELECT TRUE FROM p[xnor2InA].l=X OR p[xnor2InB].l=X => X, (p[xnor2InA].l=H AND p[xnor2InB].l=H) OR (p[xnor2InA].l=L AND p[xnor2InB].l=L) => H, ENDCASE => L; }; InvMux2Name: ROPE = Rosemary.Register[roseClassName: "InvMux2", evalSimple: InvMux2Simple]; invMux2Vdd, invMux2Gnd, invMux2A, invMux2B, invMux2selA, invMux2nOut: NAT; InvMux2: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "invMux2", name: InvMux2Name, public: Wires["Vdd", "Gnd", "A", "B", "selA", "nOut"]]; [invMux2Vdd, invMux2Gnd, invMux2A, invMux2B, invMux2selA, invMux2nOut] _ PortIndexes[ct.public, "Vdd", "Gnd", "A", "B", "selA", "nOut"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "A", "B", "selA"]; [] _ InitPorts[ct, l, drive, "nOut"]; }; InvMux2Simple: Rosemary.EvalProc = { p[invMux2nOut].l _ SELECT p[invMux2selA].l FROM H => p[invMux2A].l, L => p[invMux2B].l, ENDCASE => IF p[invMux2A].l=p[invMux2B].l THEN p[invMux2A].l ELSE X; }; BFFName: ROPE = Rosemary.Register[roseClassName: "BFF", init: BFFInit, evalSimple: BFFSimple]; bffVdd, bffGnd, bffD0, bffD1, bffD2, bffD3, bffs0, bffs1, bffs2, bffClock, bffQ, bffNQ: NAT; FFRef: TYPE = REF FFRec; FFRec: TYPE = RECORD [val, prevCK: Ports.Level]; BasicFlipFlop: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "BFF", name: BFFName, public: Wires["Vdd", "Gnd", "D0", "D1", "D2", "D3", "s0", "s1", "s2", "CK", "Q", "NQ"]]; [bffVdd, bffGnd, bffD0, bffD1, bffD2, bffD3, bffs0, bffs1, bffs2, bffClock, bffQ, bffNQ] _ PortIndexes[ct.public, "Vdd", "Gnd", "D0", "D1", "D2", "D3", "s0", "s1", "s2", "CK", "Q", "NQ"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "D0", "D1", "D2", "D3", "CK", "s0", "s1", "s2"]; [] _ InitPorts[ct, l, drive, "Q", "NQ"]; }; BFFInit: Rosemary.InitProc = { state: FFRef _ NEW[FFRec _ [X, X]]; stateAny _ state; }; BFFSimple: Rosemary.EvalProc = { state: FFRef _ NARROW[stateAny]; IF ~(state.prevCK=L AND p[bffClock].l=H) THEN {state.prevCK _ p[bffClock].l; RETURN}; state.val _ SELECT TRUE FROM p[bffs2].l=L AND p[bffs0].l=L => p[bffD0].l, p[bffs2].l=L AND p[bffs0].l=H => p[bffD1].l, p[bffs2].l=H AND p[bffs1].l=L => p[bffD2].l, p[bffs2].l=H AND p[bffs1].l=H => p[bffD3].l, ENDCASE => X; p[bffQ].l _ state.val; p[bffNQ].l _ NotL[state.val]; -- after an up transition state.prevCK _ p[bffClock].l; }; FFName: ROPE = Rosemary.Register[roseClassName: "FF", init: FFInit, evalSimple: FFSimple]; ffVdd, ffGnd, ffD, ffQ, ffNQ, ffClock: NAT; FlipFlop: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "FF", name: FFName, public: Wires["Vdd", "Gnd", "D", "Q", "NQ", "CK"]]; [ffVdd, ffGnd, ffD, ffQ, ffNQ, ffClock] _ PortIndexes[ct.public, "Vdd", "Gnd", "D", "Q", "NQ", "CK"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "D", "CK"]; [] _ InitPorts[ct, l, drive, "Q", "NQ"]; }; FFInit: Rosemary.InitProc = { state: FFRef _ NEW[FFRec _ [X, X]]; stateAny _ state; }; FFSimple: Rosemary.EvalProc = { state: FFRef _ NARROW[stateAny]; IF ~(state.prevCK=L AND p[ffClock].l=H) THEN {state.prevCK _ p[ffClock].l; RETURN}; state.val _ p[ffD].l; p[ffQ].l _ state.val; p[ffNQ].l _ NotL[state.val]; -- after an up transition state.prevCK _ p[ffClock].l; }; ClockGenName: ROPE = Rosemary.Register[roseClassName: "ClockGen", init: ClockGenInit, evalSimple: ClockGenSimple]; clockGenClock, clockGenTime: NAT; ClockGen: PUBLIC PROC [up, dn, firstEdge: NAT, initLow: BOOL] RETURNS [ct: CellType] ~ { ct _ CoreClasses.CreateUnspecified[ name: ClockGenName, public: Wires["Clock", "Time"]]; CoreProperties.PutCellTypeProp[ct, $up, NEW[NAT _ up]]; CoreProperties.PutCellTypeProp[ct, $dn, NEW[NAT _ dn]]; CoreProperties.PutCellTypeProp[ct, $firstEdge, NEW[NAT _ firstEdge]]; CoreProperties.PutCellTypeProp[ct, $initLow, NEW[BOOL _ initLow]]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: ClockGenName]; [clockGenClock, clockGenTime] _ PortIndexes[ct.public, "Clock", "Time"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: logicCutSet]; [] _ InitPorts[ct, b, drive, "Clock"]; [] _ InitPorts[ct, b, none, "Time"]; }; ClockState: TYPE = REF ClockStateRec; ClockStateRec: TYPE = RECORD [ up, dn, firstEdge: INT, initLow: BOOL, counter: INT _ 0, lastTime: BOOL _ TRUE]; ClockGenInit: Rosemary.InitProc = { state: ClockState _ NEW[ClockStateRec]; state.up _ NARROW[CoreProperties.GetCellTypeProp[cellType, $up], REF NAT]^; state.dn _ NARROW[CoreProperties.GetCellTypeProp[cellType, $dn], REF NAT]^; state.firstEdge _ NARROW[CoreProperties.GetCellTypeProp[cellType, $firstEdge], REF NAT]^; state.initLow _ NARROW[CoreProperties.GetCellTypeProp[cellType, $initLow], REF BOOL]^; state.lastTime _ p[clockGenTime].b; stateAny _ state; }; ClockGenSimple: Rosemary.EvalProc = { t0, normTime: INT; state: ClockState _ NARROW[stateAny]; IF state.lastTime=p[clockGenTime].b THEN RETURN; state.counter _ state.counter+1; t0 _ IF state.initLow THEN state.firstEdge+state.up ELSE state.firstEdge; normTime _ (state.counter-t0+state.up+state.dn) MOD (state.up+state.dn); p[clockGenClock].b _ SELECT TRUE FROM state.counter ~state.initLow, normTime< state.dn => FALSE, ENDCASE => TRUE; state.lastTime _ p[clockGenTime].b; }; StopName: ROPE = Rosemary.Register[roseClassName: "Stop", evalSimple: StopSimple]; StopInput: NAT; Stop: PUBLIC PROC [] RETURNS [ct: CellType] ~ { ct _ CoreClasses.CreateUnspecified[ name: StopName, public: Wires["ShouldBeFalse"]]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: StopName]; [StopInput] _ PortIndexes[ct.public, "ShouldBeFalse"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: logicCutSet]; [] _ InitPorts[ct, b, none, "Time"]; }; StopSimple: Rosemary.EvalProc = { IF p[StopInput].l#L THEN Rosemary.Stop[msg: "User-defined assertion is wrong", data: p, reason: $Client]; }; -- **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** RoseProbeProp: ATOM _ $RoseProbe; -- only value: $Yes SetObjectPort: PUBLIC PROC [cx: Sisyph.Context, initType: Ports.PortType _ b, initDrive: Ports.Drive _ none] = { Sisyph.Eval[cx, "coreProps _ CoreProperties.PutProp[coreProps, $PortData, NEW[Ports.PortDataRec _ [ type: initType, drive: initDrive]]]"]; }; SetObjectTesterDrive: PUBLIC PROC [cx: Sisyph.Context, initDrive: Ports.Drive _ none] = { Sisyph.Eval[cx, "coreProps _ CoreProperties.PutProp[coreProps, $PortTesterDrive, NEW[Ports.Drive _ initDrive]]"]; }; LogicTest: RosemaryUser.TestProc ~ { logicTime: NAT _ Ports.PortIndex[cellType.public, "Time"]; p[logicTime].b _ TRUE; p[logicTime].d _ drive; DO p[logicTime].b _ NOT p[logicTime].b; Eval[]; ENDLOOP; }; IsSingleSelectedAndCell: PROC [selected: CD.Instance, multiple: BOOL] RETURNS [BOOL _ FALSE] = { SELECT TRUE FROM selected=NIL => TerminalIO.WriteRope["\n** No current selection--can't do it.\n"]; multiple => TerminalIO.WriteRope["\n** Multiple instances selected--can't do it.\n"]; ~CDCells.IsCell[selected.ob] => TerminalIO.WriteRope["\n** Not a cellcan't do it.\n"]; ENDCASE => RETURN[TRUE]; }; ExtractSelectedObjAndRunRosemary: PROC [comm: CDSequencer.Command] = { ListOfDisplayWires: PROC [inst: CellInstance] RETURNS [displayWires: CoreFlat.FlatWires] ~ { wire: Wire _ inst.actual; FOR i: NAT IN [0..wire.size) DO displayWires _ CONS[NEW[CoreFlat.FlatWireRec _ [path: CoreFlat.NullPath, wire: wire[i]]], displayWires]; ENDLOOP; }; selected: CD.Instance; multiple: BOOL; sim: Rosemary.Simulation; cx: Sisyph.Context _ Sisyph.Create[comm.design]; cellType: CellType _ NIL; displayInst: CellInstance _ NIL; rct: CoreClasses.RecordCellType; logicVdd, logicGnd: NAT; [selected, multiple] _ CDOps.SelectedInstance[comm.design]; IF ~IsSingleSelectedAndCell[selected, multiple] THEN RETURN; Sisyph.Store[cx: cx, var: Sisyph.globalNamesRope, value: NEW[LIST OF ROPE _ Sisyph.List["Time", "Gnd", "Vdd"]]]; cellType _ NARROW [Sinix.Extract[obj: selected.ob, mode: Sisyph.sisyphMode, properties: selected.properties, userData: cx].result]; cellType _ CoreOps.ToBasic[cellType]; IF cellType.class#CoreClasses.recordCellClass THEN ERROR; logicVdd _ Ports.PortIndex[cellType.public, "Vdd"]; logicGnd _ Ports.PortIndex[cellType.public, "Gnd"]; [] _ Rosemary.SetFixedWire[cellType.public[logicVdd], H]; [] _ Rosemary.SetFixedWire[cellType.public[logicGnd], L]; rct _ NARROW[cellType.data]; FOR i: NAT IN [0..rct.size) DO IF CoreProperties.GetCellInstanceProp[rct[i], RoseProbeProp]#NIL THEN displayInst _ rct[i]; ENDLOOP; IF displayInst=NIL THEN ERROR; -- nothing to display sim _ RosemaryUser.TestProcedureViewer[ cellType: cellType, testButtons: LIST["Logic Test"], name: "Logic Test", displayWires: ListOfDisplayWires[displayInst], flatten: TRUE, cutSets: LIST[logicCutSet, macroCutSet]]; }; CDMenus.ImplementEntryCommand[menu: $OtherProgramMenu, entry: "Sisyph Extract and Rosemary", p: ExtractSelectedObjAndRunRosemary, key: $CoreRosemaryExtractSelectedObjAndRunRosemary]; RosemaryUser.RegisterTestProc["Logic Test", LogicTest]; END. lLogicImpl.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Last Edited by: Louis Monier August 7, 1986 2:25:55 am PDT New Class Utilities -- lib can be passed by context, once there is more than one lib Zero and One Inverter(s) Tristate Driver And Nand Or Nor Xor and Xnor Mux Basic building block for Flip-Flops Edge-Triggered Flip-Flops Clock Generator Assertion Checking -- These belong in Sch, but Sch must be redone, so in the mean time... Sisyph.Store[cx: cx, var: Sisyph.globalNamesRope, value: Sisyph.Cons["Time", Sisyph.Eval[cx, Sisyph.globalNamesRope]]]; -- Entry goes in Sisyph Menu Κρ– "cedar" style˜codešœ™Kšœ Οmœ1™Kš žœžœžœ$žœžœ˜>Kš žœžœžœ$žœžœ˜>Kš žœžœžœ$žœžœ˜>Kš žœžœžœ$žœžœ˜>Kš žœžœžœ$žœžœ˜>Kš žœžœžœ$žœžœ˜>Kš žœžœžœ$žœžœ˜>Kš žœžœžœ$žœžœ˜>Kš žœžœžœ$žœžœ˜>Kš žœžœžœ%žœžœ˜@K˜K˜—šŸ œžœžœ@žœžœžœ4žœžœžœ˜³Kš žœžœžœ žœžœ˜:Kš žœžœžœ žœžœ˜:Kš žœžœžœ žœžœ˜:Kš žœžœžœ žœžœ˜:Kš žœžœžœ žœžœ˜:Kš žœžœžœ žœžœ˜:Kš žœžœžœ žœžœ˜:Kš žœžœžœ žœžœ˜:Kš žœžœžœ žœžœ˜:Kš žœžœžœ žœžœ˜:Kš žœžœžœ"žœžœ˜=Kš žœžœžœ"žœžœ˜=K˜—šŸœžœžœžœ˜?Kšœžœžœžœ˜/—šŸœžœžœžœ˜LKš žœžœžœžœžœ˜'Kšœžœžœžœžœžœžœžœžœ˜IKšœžœžœžœžœžœžœžœžœžœžœžœžœžœžœ˜vK˜—šŸœžœžœ$˜7Kš žœžœžœžœžœ˜9K˜—šŸœžœžœ3˜EKš žœžœžœžœžœ˜7K˜——™ KšŸœžœB˜OKšŸœžœB˜OKšœ žœ˜K˜šŸœžœžœžœ˜+šœ˜Kšœ%˜%—Kšœ&˜&Kšœ$˜$Kšœ˜—KšŸ œ%˜.K˜šŸœžœžœžœ˜+šœ˜Kšœ%˜%—Kšœ&˜&Kšœ$˜$Kšœ˜K˜—KšŸ œ%˜.—™ KšŸœžœB˜OKšœžœ˜#K˜šŸœžœžœžœ˜+šœ˜Kšœ6˜6—KšœQ˜QKšœ/˜/Kšœ"˜"Kšœ˜K˜—š Ÿœžœžœžœžœ˜6Kšœ ‘˜&Kšœ˜K˜—šŸ œ˜ Kšœžœ žœžœ˜AKšœ˜——šŸ™KšŸ œžœN˜aKšœRžœ˜VK˜šŸ œžœžœžœ˜1šœ#˜#KšœI˜I—Kšœv˜vKšœA˜AKšœ˜K˜—šŸœ˜&šœ2˜2Kšœ˜Kšœ˜Kšœ˜—šžœž˜KšœM˜MKšœ ˜ Kšžœ7˜>—Kšœ˜——™KšŸœžœB˜OKšŸœžœD˜RKšŸœžœD˜RKšŸœžœD˜RKšœžœ˜#Kšœ-žœ˜1Kšœ6žœ˜:Kšœ?žœ˜CK˜š Ÿœžœžœžœžœ˜3Kšžœžœžœ‘ ˜šœ1˜1Kšœ0˜0—KšœA˜AKšœQ˜QKšœ9˜9Kšœ*˜*Kšœ"˜"Kšœ"˜"Kšœ˜—šŸ œ˜ Kšœ žœžœ˜šžœžœžœž˜&Kšžœžœžœ˜3Kšœžœ˜'Kšžœ˜—šœžœžœž˜Kšœ ˜ Kšžœ˜ —Kšœ˜K˜—šŸœžœžœžœ˜,šœ˜Kšœ@˜@—šœG˜GKšœ!˜!—Kšœ8˜8Kšœ"˜"Kšœ˜—šŸ œ˜!šœžœžœž˜Kšœžœ˜&Kšœžœ˜'Kšžœ˜ —Kšœ˜K˜—šŸœžœžœžœ˜,šœ˜KšœG˜G—šœP˜PKšœ(˜(—Kšœ?˜?Kšœ"˜"Kšœ˜—šŸ œ˜!šœžœžœž˜Kšœžœžœ˜8Kšœžœžœ˜:Kšžœ˜ —Kšœ˜K˜—šŸœžœžœžœ˜,šœ˜KšœN˜N—šœY˜YKšœ/˜/—KšœF˜FKšœ"˜"Kšœ˜—šŸ œ˜!šœžœžœž˜Kšœžœžœžœ˜JKšœžœžœžœ˜MKšžœ˜ —Kšœ˜——™KšŸœžœC˜QKšŸ œžœF˜UKšŸ œžœF˜UKšŸ œžœF˜UKšœ#žœ˜'Kšœ2žœ˜6Kšœ<žœ˜@KšœFžœ˜JK˜š Ÿœžœžœžœžœ˜4Kšžœžœžœ‘ ˜šœ2˜2Kšœ0˜0—KšœB˜BKšœU˜UKšœ9˜9Kšœ*˜*Kšœ"˜"Kšœ"˜"Kšœ˜—šŸ œ˜!Kšœ žœžœ˜šžœžœžœž˜'Kšžœžœžœ˜5Kšœžœ˜(Kšžœ˜—šœžœžœž˜Kšœ ˜ Kšžœ˜ —Kšœ˜K˜—šŸœžœžœžœ˜-šœ ˜ KšœA˜A—šœL˜LKšœ!˜!—Kšœ8˜8Kšœ"˜"Kšœ˜—šŸ œ˜"šœžœžœž˜ Kšœžœ˜(Kšœžœ˜)Kšžœ˜ —Kšœ˜K˜—šŸœžœžœžœ˜-šœ ˜ KšœH˜H—šœV˜VKšœ(˜(—Kšœ?˜?Kšœ"˜"Kšœ˜—šŸ œ˜"šœžœžœž˜ Kšœžœžœ˜;Kšœžœžœ˜=Kšžœ˜ —Kšœ˜K˜—šŸœžœžœžœ˜-šœ ˜ KšœO˜O—Kšœ˜KšœF˜FKšœ"˜"Kšœ˜—šŸ œ˜"šœžœžœž˜ Kšœžœžœžœ˜NKšœžœžœžœ˜QKšžœ˜ —Kšœ˜——™KšŸœžœ@˜LKšŸœžœB˜OKšŸœžœB˜OKšŸœžœB˜OKšœžœ˜Kšœ(žœ˜,Kšœ0žœ˜4Kšœ8žœ˜