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]<KernalLimit,

ENDCASE => 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šœžœ	˜%Kšœ#˜#Kšœ˜Kšœ
˜
K˜Kšœžœ˜Kšœ˜Kšœ˜Kšœžœ˜Kšœ˜Kšœžœ˜1Kšœ2˜2Kšœ˜Kšœ
˜
K˜K˜K˜K˜K˜�—šžœ˜	Kšœ˜K˜K˜�—šžœ˜šžœ˜KšœO™O—šžœ˜K™0Kšœžœ3˜<Kšœ+˜+Kšžœ
žœžœžœ˜FK˜—K˜�—˜Kšœo™oKšœ  ˜=K˜�šœ4™4Kšœ7™7—šžœž˜šžœžœž˜šœ/˜/Kšœª™ªKšœ˜Kšžœžœ˜K˜—šœ˜Kšœ™Kšœ˜Kšžœžœ˜K˜—Kšžœ˜K˜�——šžœžœ˜Kšœ)™)Kšœ/˜/KšœP˜Pšœ˜Kšœ4™4—šžœžœžœžœ˜>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��