; Checksum.mu -- Ram ByteCode to compute PupChecksums ; Last modified HGM June 30, 1980 6:02 PM ; Last modified Johnsson; September 22, 1980 9:12 AM ; Assumes that AltoConsts23.mu and XMesaRAM.mu (which includes Mesab.mu) ; have been included and the following predef has appeared. ;%7, 1777, 1402, PupChecksum; ; PupChecksum: ; PROCEDURE[initialSum: CARDINAL, address: POINTER, count: CARDINAL] ; RETURNS[resultSum: CARDINAL] ; initialSum: must be zero initially (used to restart after interrupts). ; address: address of block. ; count: length of block (words) NB: Zero won't work! ; Returns the ones-complement add-and-cycle checksum over the block. ; Entry point is Ram address 1402. ; Timing: 9 cycles/word ; 2484 cycles (= 422 microseconds) per maximum-length Pup $MTEMP $R25; !1,2,PCMayI,PCNoI; !1,2,PCDisI,PCDoI; !1,2,PCOkCy,PCZCy; !1,2,PCNoCy,PCCy; !1,2,PCLoop,PCDone; !1,2,PCNoMZ,PCMinZ; !1,1,PCDoI1; PupChecksum: L_ stk0; Must keep partial sum in R reg (not S) temp_ L; MAR_ L_ stk1, :PCLp1; Start fetch of first word ; Top of main loop. ; Each iteration adds the next data word to the partial sum, adds 1 if ; the addition caused a carry, and left-cycles the result one bit. ; Due to ALU function availability, the first addition is actually done ; as (new data word)+(partial sum -1)+1, which causes an erroneous carry ; if (partial sum)=0. Hence we make a special test for this case. PCLoop: MAR_ L_ stk1+1; Start fetch of next word PCLp1: SINK_ NWW, BUS=0; Test for interrupts stk1_ L, :PCMayI; [PCMayI, PCNoI] Update pointer PCNoI: T_ temp-1, BUS=0, :PCDisI; [PCDisI, PCDoI] Get partial sum -1 PCDisI: L_ T_ MD+T+1, :PCOkCy; [PCOkCy, PCZCy] Add new word +1 PCOkCy: L_ stk2-1, ALUCY; Test for carry out, decrement count PCLp2: stk2_ L, :PCNoCy; [PCNoCy, PCCy] Update count PCNoCy: L_ T, SH=0, TASK, :PCLast; No carry, test count=0 PCCy: MTEMP_ L, L_ T_ 0+T+1, SH=0, TASK; Do end-around carry, test count=0 PCLast: temp_ L MLSH 1, :PCLoop; [PCLoop, PCDone] Left cycle 1 ; Here if partial sum was zero -- suppress test of bogus carry caused by ; MD+(temp-1)+T+1 computation. PCZCy: L_ stk2-1, :PCLp2; ; Here when done PCDone: L_ temp+1; Test for minus zero (ones-complement) L_ ONE, SH=0; Define stack to contain one thing PCDn1: stkp_ L, L_ 0, :PCNoMZ; [PCNoMZ, PCMinZ] PCNoMZ: L_ temp, TASK, :PCGoEm; PCMinZ: TASK; Minus zero, change to plus zero PCGoEm: stk0_ L, :Emulator; Put result on stack ; Here when possible interrupt pending. ; Note that if the interrupt does not take, we read MD one cycle too late. ; This works only on Alto-II. PCMayI: SINK_ wdc, BUS=0, :PCNoI; Let it take only if wdc=0 ; Here when interrupt definitely pending. ; Assume that the JRAM was the A-byte, so back up mpc and set ib to zero ; to force the interpreter to re-fetch the current word and also test again ; for the interrupt we know is pending. PCDoI: L_ mpc-1; [PCDOI1] Back up mpc, squash BUS=0 PCDoI1: mpc_ L, L_ 0, TASK; ib_ L; ib_ 0 L_ stkp+1, :PCDn1; Push Ram address back onto stack Emulator: SWMODE; Switch to Rom1 :romnextA; Mesa emulator entry point