DIRECTORY Basics USING [BITAND, CARD], DragOpsCross USING [Byte, bytesPerWord, EUStackSize, FieldDescriptor, FourBytes, IFUOverflow, IFUStackSize, IFUStatusRec, Inst, KernalLimit, OnesWord, ProcessorRegister, TrapIndex, Word, ZerosWord], DragOpsCrossUtils USING [BytePCToWordAddress, ByteToCard, BytesToHalf, BytesToWord, CardToWord, DoubleWordShiftLeft, DragAnd, DragNot, DragOr, DragXor, HalfToCard, IntToWord, SingleWordShiftLeft, SingleWordShiftRight, TrapIndexToBytePC, VanillaAdd, VanillaSub, WordAddressToBytePC, WordToBytes, WordToCard, WordToInt], LizardHeart USING [ALUHelper, ALUOps, CacheBase, ChangeLogger, Control, InstBuffer, InstBufferRep, LizardIFUStackIndex, LizardIFUStackSize, NoFault, Processor, ProcessorRep, RegChangeProc, RegToWord, StackPlus, TrapPC, WordToReg], LizardLiver USING [Execute], PrincOpsUtils USING [LongCopy], Rope USING [ROPE]; LizardHeartImpl: CEDAR PROGRAM IMPORTS Basics, DragOpsCrossUtils, LizardHeart, LizardLiver, PrincOpsUtils EXPORTS LizardHeart = BEGIN OPEN DragOpsCross, DragOpsCrossUtils, LizardHeart; CARD: TYPE = Basics.CARD; CurrentIFUVersion: [0..255] _ 1; InstBufferIndex: TYPE = [0..64); WordsInBuffer: NAT _ 8; MaxMask: CARDINAL _ WordsInBuffer*bytesPerWord - 1; MaskInstBufferIndex: PROC [index: CARDINAL] RETURNS [InstBufferIndex] = INLINE { RETURN [LOOPHOLE[Basics.BITAND[index, MaxMask]]]; }; NewProcessor: PUBLIC PROC [ifuCache,euCache: CacheBase, logger: ChangeLogger] RETURNS [p: Processor] = { initStatus: IFUStatusRec _ [version: CurrentIFUVersion, rescheduleKeep: TRUE]; p _ NEW[ProcessorRep]; p.ifuCache _ ifuCache; p.euCache _ euCache; p.logger _ logger; p.eldest _ 1; p.youngest _ 1; p.stackEntries _ 0; p.regs[ifuPC] _ TrapPC[ResetTrap]; p.regsGood[euConstant] _ TRUE; -- constant register 0 = 0 (it's a ROM) p.regsGood[ifuStatus] _ TRUE; p.regs[ifuStatus] _ LOOPHOLE[initStatus]; p.instBuffer _ NEW[InstBufferRep[WordsInBuffer]]; }; FlushInstBuffer: PUBLIC PROC [processor: Processor] = { instBuffer: InstBuffer = processor.instBuffer; delta: INT = WordToInt[instBuffer.nextPC] - WordToInt[instBuffer.basePC]; IF delta > 0 THEN { validBytes: INT = instBuffer.validWords*bytesPerWord; IF validBytes > delta THEN instBuffer.bytesDiscarded _ instBuffer.bytesDiscarded + validBytes-delta; }; instBuffer.validWords _ 0; instBuffer.forcedEmpty _ instBuffer.forcedEmpty + 1; }; InstructionExecute: PUBLIC PROC [processor: Processor] = { thisPC: Word _ processor.regs[ifuPC]; newPC: Word _ thisPC; rtnPC: Word; control: Control _ nextInst; inst: Inst; rest: Word; oldStatus: IFUStatusRec =LOOPHOLE[processor.regs[ifuStatus]]; status: IFUStatusRec _ oldStatus; regL: Word _ processor.regs[ifuL]; cycles: CARDINAL _ 0; rCycles: CARDINAL _ 0; initCycles: INT _ processor.stats.cycles; youngest: CARDINAL _ processor.youngest; nBytes: CARDINAL _ 0; word: Word; wordAddr: Word; rbi: [0..bytesPerWord); tx: TrapIndex _ NoFault; valid: InstBufferIndex _ 0; -- valid bytes in inst buffer AFTER newPC p: Processor = processor; -- for a short name instBuffer: InstBuffer _ p.instBuffer; instBufferPtr: LONG POINTER; max: CARDINAL = instBuffer.max * bytesPerWord; -- max bytes in buffer ForceBufferEmpty: PROC = INLINE { instBuffer.validWords _ 0; instBuffer.forcedEmpty _ instBuffer.forcedEmpty + 1; IF valid # 0 THEN { instBuffer.bytesDiscarded _ instBuffer.bytesDiscarded + valid; valid _ 0; }; }; IsEUStackOverflow: PROC [regS: ProcessorRegister] RETURNS [BOOL] = INLINE { RETURN [ LOOPHOLE[LOOPHOLE[regS, CARDINAL] -LOOPHOLE[WordToReg[processor.regs[ifuSLimit]], CARDINAL]+EUStackSize, CARDINAL] MOD EUStackSize IN [0..16) ]; }; CauseTrap: PROC [code: TrapIndex] = { regS: ProcessorRegister _ StackPlus[WordToReg[p.regs[ifuS]], 1]; oldStatus: Word = LOOPHOLE[status]; rtnPC _ thisPC; IF WillPushOverflow[p] THEN code _ IFUStackOverflowTrap; newPC _ TrapPC[code]; control _ doAbort; p.regs[ifuS] _ RegToWord[regS]; IF p.logger # NIL THEN { regChange: RegChangeProc _ p.logger.regChange; IF regChange # NIL THEN regChange[p.logger.data, p, regS, p.regs[regS], oldStatus]; }; p.regs[regS] _ oldStatus; status.trapsEnabled _ FALSE; status.userMode _ FALSE; p.regs[ifuStatus] _ LOOPHOLE[status]; cycles _ cycles + 4; -- a rough guess tx _ code; IF code = IFUStackOverflowTrap THEN p.stats.stackOver _ p.stats.stackOver + 1; }; FlushInstWord: PROC = INLINE { vw: CARDINAL _ instBuffer.validWords - 1; instBuffer.basePC _ IntToWord[WordToInt[instBuffer.basePC] + bytesPerWord]; instBuffer.validWords _ instBuffer.validWords - 1; IF vw # 0 THEN TRUSTED { PrincOpsUtils.LongCopy[from: @instBuffer[1], nwords: instBuffer.validWords*SIZE[Word], to: @instBuffer[0]]; }; instBuffer.validWords _ vw; }; IF p.resetRequested THEN { status _ [version: CurrentIFUVersion, rescheduleKeep: TRUE]; p.regs[ifuStatus] _ LOOPHOLE[status]; thisPC _ newPC _ TrapPC[ResetTrap]; p.youngest _ youngest _ 0; p.eldest _ 1; p.stackEntries _ 0; p.resetRequested _ FALSE; p.regs[ifuL] _ CardToWord[1]; p.regs[ifuS] _ ZerosWord; p.euCarry _ FALSE; ForceBufferEmpty[]; p.instBuffer _ NEW[InstBufferRep[WordsInBuffer]]; p.instBuffer.forcedEmpty _ instBuffer.forcedEmpty; instBuffer _ p.instBuffer; p.stats _ []; p.ifuCache.stats _ []; p.euCache.stats _ []; initCycles _ cycles _ 0; }; TRUSTED { instBufferPtr _ @instBuffer[0]; }; IF newPC # instBuffer.nextPC THEN ForceBufferEmpty[] ELSE { used: INT _ WordToInt[newPC] - WordToInt[instBuffer.basePC]; valid _ instBuffer.validWords*bytesPerWord; IF used > 0 AND used < valid THEN valid _ valid - used ELSE valid _ 0; }; { start: InstBufferIndex _ 0; -- byte index in buffer of newPC IF status.trapsEnabled THEN SELECT TRUE FROM IsEUStackOverflow[WordToReg[p.regs[ifuS]]] => { tx _ EUStackOverflowTrap; GO TO trapEarly; }; status.reschedule => { tx _ RescheduleTrap; GO TO trapEarly; }; ENDCASE; IF valid = 0 THEN { [wordAddr, rbi] _ BytePCToWordAddress[[newPC]]; [word, tx, rCycles] _ p.ifuCache.fetch[p.ifuCache, wordAddr, initCycles+cycles]; cycles _ cycles + 1; IF tx # NoFault THEN {tx _ IFUPageFaultTrap; GO TO trapEarly}; IF rCycles # 0 THEN { cycles _ cycles + rCycles; instBuffer.busyUntil _ p.ifuCache.sharedBase.busyUntil; }; valid _ bytesPerWord - rbi; instBuffer.validWords _ 1; instBuffer.basePC _ WordAddressToBytePC[wordAddr]; instBuffer[0] _ word; }; start _ WordToInt[newPC] - WordToInt[instBuffer.basePC]; IF start >= max THEN ERROR; word _ instBuffer[start/bytesPerWord]; inst _ LOOPHOLE[WordToBytes[word][start MOD bytesPerWord]]; nBytes _ LOOPHOLE[inst, CARDINAL] / 64; IF nBytes = 0 THEN nBytes _ IF LOOPHOLE[inst, CARDINAL] < 40B THEN 1 ELSE 5; IF valid < nBytes THEN { IF instBuffer.validWords = instBuffer.max THEN FlushInstWord[]; [wordAddr, rbi] _ BytePCToWordAddress[[IntToWord[WordToInt[newPC] + valid]]]; [word, tx, rCycles] _ p.ifuCache.fetch[p.ifuCache, wordAddr, initCycles+cycles]; cycles _ cycles + 1; IF rCycles # 0 THEN { cycles _ cycles + rCycles; rCycles _ 0; instBuffer.busyUntil _ p.ifuCache.sharedBase.busyUntil; }; IF tx # NoFault THEN {tx _ IFUPageFaultTrap; GO TO trapEarly}; start _ WordToInt[newPC] - WordToInt[instBuffer.basePC]; instBuffer[start/bytesPerWord + 1] _ word; instBuffer.validWords _ instBuffer.validWords + 1; valid _ valid + bytesPerWord; }; IF nBytes > 1 THEN TRUSTED { instBufferPtr: LONG POINTER TO PACKED ARRAY InstBufferIndex OF Byte _ LOOPHOLE[@instBuffer[0]]; SELECT nBytes FROM 5 => { rest _ BytesToWord[[ instBufferPtr[MaskInstBufferIndex[start+1]], instBufferPtr[MaskInstBufferIndex[start+2]], instBufferPtr[MaskInstBufferIndex[start+3]], instBufferPtr[MaskInstBufferIndex[start+4]] ]]; }; 3 => { rest _ CardToWord[HalfToCard[BytesToHalf[[ instBufferPtr[MaskInstBufferIndex[start+1]], instBufferPtr[MaskInstBufferIndex[start+2]] ]]]]; }; 2 => { rest _ CardToWord[ByteToCard[ instBufferPtr[MaskInstBufferIndex[start+1]] ]]; }; ENDCASE => ERROR; }; newPC _ IntToWord[WordToInt[newPC] + nBytes]; valid _ valid - nBytes; IF instBuffer.busyUntil <= initCycles+cycles THEN { IF valid <= max-bytesPerWord THEN { fetchPC: Word _ IntToWord[WordToInt[newPC] + valid]; IF instBuffer.validWords = instBuffer.max THEN FlushInstWord[]; [wordAddr, rbi] _ BytePCToWordAddress[[fetchPC]]; IF rbi # 0 THEN ERROR; -- rats! we blew it! [word, tx, rCycles] _ p.ifuCache.fetch[p.ifuCache, wordAddr, initCycles+cycles]; IF rCycles # 0 THEN { instBuffer.busyUntil _ p.ifuCache.sharedBase.busyUntil; p.stats.lookaheadRejects _ p.stats.lookaheadRejects + rCycles; }; IF tx = NoFault THEN { instBuffer[instBuffer.validWords] _ word; instBuffer.validWords _ instBuffer.validWords + 1; }; tx _ NoFault; }; }; instBuffer.nextPC _ newPC; p.stats.cycles _ p.stats.cycles+cycles; p.stats.instBufferCycles _ p.stats.instBufferCycles+cycles; cycles _ 0; [newPC, rtnPC, control] _ LizardLiver.Execute[p, thisPC, inst, rest]; status _ LOOPHOLE[p.regs[ifuStatus]]; EXITS trapEarly => CauseTrap[tx]; }; thisPC _ newPC; SELECT control FROM nextInst => {}; doSwitch => ForceBufferEmpty[]; doCall, doAbort, doReturn => { ForceBufferEmpty[]; IF control = doReturn THEN { currentSize: NAT _ p.stackEntries; SELECT currentSize FROM = 0 => { SIGNAL OutsideEnvelope["IFU control stack empty on return!"]; thisPC _ TrapPC[StackUnderflowTrap]; GO TO badGnus; }; > IFUStackSize => { SIGNAL OutsideEnvelope["IFU control stack is too full during return!"]; GO TO badGnus; }; > IFUOverflow => IF status.trapsEnabled THEN { SIGNAL OutsideEnvelope["IFU control stack is too full during return!"]; GO TO badGnus; }; ENDCASE; p.stackEntries _ currentSize - 1; thisPC _ p.ifuStack[youngest].pc; p.regs[ifuL] _ regL _ RegToWord[p.ifuStack[youngest].regL]; p.youngest _ youngest _ (youngest + (LizardIFUStackSize - 1)) MOD LizardIFUStackSize; EXITS badGnus => {}; } ELSE { newSize: NAT _ p.stackEntries+1; IF newSize > IFUStackSize THEN SIGNAL OutsideEnvelope["IFU control stack too full!"] ELSE { p.stackEntries _ newSize; p.youngest _ youngest _ (youngest + 1) MOD LizardIFUStackSize; }; p.ifuStack[youngest] _ [rtnPC, WordToReg[regL]]; ForceBufferEmpty[]; IF tx # NoFault THEN IF p.logger # NIL AND p.logger.instDone # NIL THEN p.logger.instDone[p.logger.data, p, newPC, rtnPC, doAbort, cycles]; }; IF p.lastCallRtn + 3 >= p.stats.instructions THEN { cycles _ cycles + 2; p.stats.returnInterlockCycles _ p.stats.returnInterlockCycles + 2; }; p.lastCallRtn _ p.stats.instructions; }; ENDCASE => ERROR; p.regs[ifuPC] _ thisPC; p.stats.cycles _ p.stats.cycles+cycles; p.stats.instBytes _ p.stats.instBytes+nBytes; }; DoALUOp: PUBLIC PROC [processor: Processor, wordA,wordB: Word, op: ALUOps, trap: TrapIndex] RETURNS [res: Word, resCode: TrapIndex _ NoFault] = { carryOut, overflow, boundsCheck, illegalLisp: BOOL _ FALSE; carryIn: BOOL _ processor.euCarry; SELECT op FROM SAdd => { [res, ] _ WordCarryAdd[wordA, wordB, carryIn]; SELECT ALUHelper[wordA[0], wordB[0], res[0]] FROM a0b0c1, a1b1c0 => {overflow _ TRUE}; ENDCASE; }; UAdd => [res, carryOut] _ WordCarryAdd[wordA, wordB, carryIn]; SSub => { [res, ] _ WordCarryAdd[wordA, DragNot[wordB], NOT carryIn]; SELECT ALUHelper[wordA[0], wordB[0], res[0]] FROM a0b1c1, a1b0c0 => overflow _ TRUE; ENDCASE; }; USub => { [res, carryOut] _ WordCarryAdd[wordA, DragNot[wordB], NOT carryIn]; carryOut _ NOT carryOut; }; LAdd, LSub => { res _ IF op = LAdd THEN VanillaAdd[wordA, wordB] ELSE VanillaSub[wordA, wordB]; IF res[0] # res[1] OR res[1] # res[2] OR wordA[0] # wordA[1] OR wordA[1] # wordA[2] OR wordB[0] # wordB[1] OR wordB[1] # wordB[2] THEN illegalLisp _ TRUE }; VAdd => {res _ VanillaAdd[wordA, wordB]; carryOut _ carryIn}; VSub => {res _ VanillaSub[wordA, wordB]; carryOut _ carryIn}; And => {res _ DragAnd[wordA, wordB]; RETURN}; Or => {res _ DragOr[wordA, wordB]; RETURN}; Xor => {res _ DragXor[wordA, wordB]; RETURN}; BndChk => { boundsCheck _ WordCarryAdd[wordA, DragNot[wordB], TRUE].carryOut; res _ wordA; carryOut _ carryIn; }; ENDCASE => ERROR; resCode _ (IF (SELECT trap FROM ALUCondFalse => FALSE, ALUCondEZ => res = ZerosWord, ALUCondLZ => WordToInt[res] < 0, ALUCondLE => WordToInt[res] <= 0, ModeFault => TRUE, ALUCondNE => res = ZerosWord, ALUCondGE => WordToInt[res] >= 0, ALUCondGZ => WordToInt[res] > 0, ALUCondOver => overflow, ALUCondBC => boundsCheck, ALUCondIL => illegalLisp, ALUCondDO => FALSE, -- not yet implemented ALUCondNotOver => NOT overflow, ALUCondNB => NOT boundsCheck, ALUCondNI => NOT illegalLisp, AddressCheckFault => WordToCard[res] ERROR) THEN trap ELSE NoFault); IF resCode = NoFault THEN processor.euCarry _ carryOut; }; WordCarryAdd: PROC [wordA, wordB: Word, carryIn: BOOL] RETURNS [wordC: Word, carryOut: BOOL _ FALSE] = { cardA: CARD _ WordToCard[wordA]; cardB: CARD _ WordToCard[wordB]; cardC: CARD _ cardA+cardB; SELECT cardC FROM < cardA, < cardB => carryOut _ TRUE; ENDCASE; IF carryIn THEN {cardC _ cardC+1; IF cardC = 0 THEN carryOut _ TRUE}; wordC _ CardToWord[cardC]; }; FieldUnit: PUBLIC PROC [Left,Right: Word, fd: FieldDescriptor] RETURNS [out: Word] = { shifter: Word = DoubleWordShiftLeft[Left, Right, fd.shift]; mask: Word _ IF fd.mask >= 32 THEN OnesWord ELSE SingleWordShiftRight[OnesWord, 32-fd.mask]; IF fd.insert THEN { mask _ DragAnd[mask, SingleWordShiftLeft[OnesWord, fd.shift]]; out _ DragOr[DragAnd[mask, shifter], DragAnd[DragNot[mask], Right]]; } ELSE out _ DragAnd[mask, shifter]; }; WillPushOverflow: PUBLIC PROC [processor: Processor] RETURNS [BOOL] = { IF processor.stackEntries < IFUOverflow-1 THEN RETURN [FALSE] ELSE { status: IFUStatusRec _ LOOPHOLE[processor.regs[ifuStatus]]; SELECT processor.stackEntries FROM = IFUOverflow-1 => {}; < IFUStackSize => IF status.trapsEnabled THEN SIGNAL OutsideEnvelope["IFU control stack too full with traps enabled"]; ENDCASE => SIGNAL OutsideEnvelope["IFU control stack has more than IFUStackSize entries"]; RETURN [status.trapsEnabled]; }; }; OutsideEnvelope: PUBLIC SIGNAL [explanation: Rope.ROPE] = CODE; END. ¼LizardHeartImpl.mesa Copyright c 1984, 1985, 1986 by Xerox Corporation. All rights reserved. Russ Atkinson (RRA) April 1, 1986 5:13:25 pm PST McCreight, January 30, 1986 4:35:51 pm PST The current version # of the IFU, stored in status.version max # of words allowed # of Dragon words in the instruction buffer (power of two) Mask for valid bytes in the buffer This routine flushes the instruction buffer. This occurs on a bad jump prediction, a trap, or an xop. ForceBufferEmpty forces the instruction buffer to be empty. It is a faster local version of FlushInstBuffer. All traps push the status onto the EU stack, and set the status to have traps disabled and be in kernel mode. If an IFU stack overflow would result, then that has precedence over anything else. If an EU stack overflow would result from the push, then that is ignored. This routine was cribbed from LizardHeartImpl and simplified. IFUStackOverflow has precedence over other traps Flushes one word from the inst buffer, shifting the words down so that instBuffer[0] corresponds to inst.basePC. We also update instBuffer.basePC forward one word, and instBuffer.validWords backwards one word. Force the machine to its reset state. The state we force it to here is highly speculative. If the PC is not the next one in the sequence then flush the instruction buffer Compute the number of valid bytes in the buffer. Fetch the next instruction byte in the instruction buffer, causing a refill if the instruction buffer is empty. Between instructions we have the following priority: EUStackOverflowTrap > RescheduleTrap > IFUPageFaultTrap There was an EU stack overflow caused by the previous instruction. This may be because a previous SIP or RETK instruction enabled traps. Should this ever really happen? Take a reschedule trap. need to fill the inst buffer from scratch The cache takes a cycle to come back with the answer A page fault has occurred during an instruction fetch. Go freak out. Account for the number of reject cycles. Also keep track of the next time that the ifu cache will be available. At this point we have at least one valid byte in the buffer. This is enough to determine the instruction and how many bytes must follow. We must make sure that we have enough bytes in the instruction buffer to execute the whole instruction. This simplifies things later, to be sure. Things are a little simpler because we know we are fetching a full word that will be appended onto the current valid stuff. Account for cache access time Account for the number of reject cycles. Also keep track of the next time that the ifu cache will be available. A page fault has occurred during an operand byte fetch. Go freak out. Move the four bytes from the fetched word into the instruction buffer. Move the bytes from the instruction buffer to rest. RRA: highest byte is first in stream, and so on Try to fetch ahead if the bus is not busy, and we need more bytes in the instruction buffer. Note that this may cause more contention for the bus than we might like, but that the bytes should be ready at the proper time in straight-line code. The instruction buffer is not trying to fetch anything from the cache, so we can use the cache to try to get the next instruction. There is room to get more words into the buffer We have completely filled the inst buffer, but still need more, so shift out the lowest address word, and update the base address and # of bytes valid. The reject cycles occur in the background, and are not counted towards elapsed cycles. But we do keep track of the next time that the ifu cache will be available. The fetch was successful, so we can put more bytes into the inst buffer. Note that we restrict the max bytes in the buffer to be a multiple of bytesPerWord. There will be no wraparound in the buffer for this word fetch. Make sure that the readahead fault does not show up later. Update the cycle count to allow EU cache to delay properly for busy bus Finally, we get to execute the instruction we fetched. Refetch status in case it changed during the instruction Continue with the new PC. This will be the case even if we are branching. A mispredicted jump will have cleared the instruction buffer in LizardLiver.Execute. Continue with the new PC, but also flush the instruction buffer. This is the case for mispredicted jumps, or for stack jumps. For doCall & doAbort, just push the PC, the overflow checking was done by the instruction execution. We get here due to an early fault (like an IFUPageFault). The idea is to log the completion of the instruction, although no instruction was really started! This aids "shadow" simulations like McCreight's. We must delay to allow changes in the IFU stack from the last call/return to become stable. This test is somewhat conservative, since multi-cycle instructions will allow the ifuStack to be stable sooner than this. However, this is a cheap way to estimate this extra delay. Utility Routines for manipulating data (incomplete) Calculate the result word and carryOut Detarmine the returned condition code There is the possibility that the carry out should NOT be set if the returned code # ALUCondFalse. One of these days we should find out if this is true. The shifter output has the input double word shifted left by fd.shift bits The default mask has fd.mask 1s right-justified in the word fd.insert => clear rightmost fd.shift bits of the mask 1 bits in the mask select the shifter output 0 bits in the mask select bits from Right 1 bits in the mask select the shifter output Ê ˜codešœ™Kšœ Ïmœ=™HK™0K™*—˜šÏk ˜ Kšœžœžœžœ˜Kšœ žœ´˜ÆKšœžœ§˜¾Kšœ žœÕ˜æKšœ žœ ˜Kšœžœ ˜Kšœžœžœ˜——headšœžœž˜KšžœC˜JKšžœ ˜Kšœžœžœ.˜:K˜Kšžœžœ žœ˜K˜—šœ ˜ Kšœ:™:K˜—šœžœ ˜ Kšœ™—K˜šœžœ˜Kšœ:™:—šœ žœ"˜3Kšœ"™"—K˜š Ïnœžœ žœžœžœ˜PKšžœžœžœ˜1K˜K˜—šŸ œžœžœ5žœ˜hKšœHžœ˜NKšœžœ˜Kšœ˜Kšœ˜Kšœ˜K˜ K˜K˜Kšœ"˜"KšœžœÏc'˜FKšœžœ˜Kšœžœ ˜)Kšœžœ˜1K˜K˜—šŸœžœžœ˜7Kšœf™fKšœ.˜.Kšœžœ?˜Išžœ žœ˜Kšœ žœ&˜5šžœž˜KšœI˜I—K˜—Kšœ˜Kšœ4˜4K˜K˜—šŸœžœžœ˜:Kšœ%˜%Kšœ˜Kšœ ˜ Kšœ˜Kšœ ˜ Kšœ ˜ Kšœžœ˜=Kšœ!˜!Kšœ"˜"Kšœžœ˜Kšœ žœ˜Kšœ žœ˜)Kšœ žœ˜(Kšœžœ˜Kšœ ˜ Kšœ˜K˜Kšœ˜Kšœ )˜FKšœ ˜.Kšœ&˜&Kšœžœžœ˜Kšœžœ# ˜FK˜šŸœžœžœ˜!Kšœm™mKšœ˜Kšœ4˜4šžœ žœ˜Kšœ>˜>Kšœ ˜ K˜—K˜—š Ÿœžœžœžœžœ˜KKšžœžœžœžœžœ'žœžœžœ žœ ˜™K˜—šŸ œžœ˜%Kšœ™Kšœ=™=Kšœ@˜@Kšœžœ ˜#K–20 sp tabStopsšœ˜–20 sp tabStopsšžœž˜K–20 sp tabStopsšœ0™0K–20 sp tabStopsšœ˜—K–20 sp tabStopsšœ˜K–20 sp tabStopsšœ˜K–20 sp tabStopsšœ˜šžœ žœžœ˜Kšœ.˜.Kšžœ žœžœ<˜SK˜—K–20 sp tabStopsšœ˜K–20 sp tabStopsšœžœ˜K–20 sp tabStopsšœžœ˜K–20 sp tabStopsšœžœ ˜%K–20 sp tabStopsšœ ˜&K˜ Kšžœžœ+˜NK˜—šŸ œžœžœ˜KšœÒ™ÒKšœžœ˜)KšœK˜KKšœ2˜2šžœžœžœ˜KšœKžœ˜kK˜—Kšœ˜K˜K˜—šžœžœ˜Kšœ[™[Kšœ6žœ˜KšœE™E—šžœ žœ˜Kšœp™pK˜Kšœ7˜7K˜—Kšœ˜Kšœ˜Kšœ2˜2Kšœ˜K˜—Kšœ‰™‰K˜Kšœ8˜8Kšžœžœžœ˜Kšœ&˜&Kšœžœžœ˜;Kšœ žœžœ˜'Kšžœ žœ žœžœžœžœžœ˜Lšžœžœ˜Kšœ™Kšžœ(žœ˜?KšœM˜MKšœP˜Pšœ˜K™—šžœ žœ˜Kšœp™pK˜Kšœ ˜ Kšœ7˜7K˜—šžœžœžœžœ ˜>KšœF™F—K˜KšœF™FKšœ8˜8Kšœ*˜*Kšœ2˜2Kšœ˜K˜—K˜K™3šžœ žœžœ˜Kšœ/™/Kšœžœžœžœžœžœžœžœ˜_šžœž˜˜šœ˜Kšœ,˜,Kšœ,˜,Kšœ,˜,Kšœ+˜+K˜—K˜—˜šœ*˜*Kšœ,˜,Kšœ+˜+Kšœ˜—K˜—˜šœ˜Kšœ+˜+Kšœ˜—K˜—Kšžœžœ˜—K˜—K˜Kšœ-˜-Kšœ˜K˜Kšœó™óšžœ+žœ˜3Kšœ‚™‚šžœžœ˜#Kšœ/™/Kšœ4˜4šžœ(žœ˜?Kšœ—™——Kšœ1˜1Kšžœ žœžœ ˜,KšœP˜Pšžœ žœ˜Kšœ£™£Kšœ7˜7Kšœ>˜>K˜—šžœžœ˜KšœÝ™ÝKšœ)˜)Kšœ2˜2K˜—šœ ˜ Kšœ:™:—K˜—Kšœ˜—K˜Kšœ˜K˜KšœG™GKšœ'˜'Kšœ;˜;Kšœ ˜ K˜Kšœ6™6KšœE˜Ešœ žœ˜%Kšœ8™8—K˜šž˜Kšœ˜—K˜—K˜Kšœ˜šžœ ž˜šœ˜Kšœ ™ —šœ ˜ Kšœ~™~Kšœ˜—šœ˜Kšœ˜šžœ˜šžœ˜Kšœ žœ˜"šžœ ž˜˜Kšžœ7˜=Kšœ$˜$Kšžœžœ ˜K˜—˜KšžœA˜GKšžœžœ ˜K˜—šœ˜šžœžœ˜KšžœA˜GKšžœžœ ˜K˜——Kšžœ˜—Kšœ!˜!Kšœ!˜!Kšœ;˜;Kšœ>žœ˜UKšžœ˜K˜—šžœ˜Kšœd™dKšœ žœ˜ šžœ˜Kšž œ/˜:šžœ˜Kšœ˜Kšœ'žœ˜>K˜——Kšœ0˜0K˜šžœž˜KšœÎ™Îš žœ žœžœžœž˜2KšœC˜C——K˜——šžœ+žœ˜3Kšœ’™’Kšœ˜KšœB˜BK˜—Kšœ%˜%Kšœ˜—Kšžœžœ˜—Kšœ˜Kšœ'˜'Kšœ-˜-K˜K˜—šœ3™3K˜šŸœžœžœHžœ.˜‘Kšœ.žœžœ˜;Kšœ žœ˜"K˜Kšœ&™&šžœž˜šœ ˜ Kšœ.˜.šžœ'ž˜1Kšœžœ˜$Kšžœ˜—K˜—šœ˜Kšœ6˜6—šœ ˜ Kšœ.žœ ˜;šžœ'ž˜1Kšœžœ˜"Kšžœ˜—K˜—šœ ˜ Kšœ6žœ ˜CKšœ žœ ˜K˜—šœ˜Kšœžœ žœžœ˜Oš žœžœžœžœžœžœž˜†Kšœž˜—K˜—Kšœ=˜=Kšœ=˜=Kšœ%žœ˜-Kšœ#žœ˜+Kšœ%žœ˜-šœ ˜ Kšœ2žœ ˜AKšœ ˜ Kšœ˜Kšœ˜—Kšžœžœ˜K˜—Kšœ%™%šœ žœžœž˜Kšœžœ˜Kšœ˜Kšœ ˜ Kšœ!˜!K˜Kšœ žœ˜Kšœ˜Kšœ!˜!Kšœ ˜ K˜Kšœ˜Kšœ˜Kšœ˜Kšœ žœ ˜*K˜Kšœžœ ˜Kšœ žœ ˜Kšœ žœ ˜Kšœ1˜1K˜Kšžœžœžœžœ ˜*—K˜šžœžœ˜7Kšœ3žœc™™—K˜K˜—š Ÿ œžœžœžœžœžœ˜hKšœžœ˜ Kšœžœ˜ Kšœžœ˜šžœž˜Kšœžœ˜$Kšžœ˜—Kš žœ žœžœ žœ žœ˜EKšœ˜K˜K˜—šŸ œžœžœ)žœ˜Všœ;˜;KšœJ™J—šœ žœžœ žœ,˜\Kšœ;™;—šžœ ˜ šžœ˜šœ>˜>Kšœ7™7—šœD˜DKšœ,™,Kšœ)™)—K˜—šž˜šœ˜Kšœ,™,———K˜K˜—š Ÿœžœžœžœžœ˜Gš žœ(žœžœžœžœ˜DKšœžœ˜;šžœž˜"Kšœ˜šœ˜šžœž˜KšžœB˜H——šžœ˜ KšžœI˜O——Kšžœ˜K˜—K˜K˜—š œžœžœžœžœ˜?K˜——Kšžœ˜—…—6]n