; 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