; IfsPupChecksum.mu
; Copyright Xerox Corporation 1979, 1980

; Last modified by Taft, February 26, 1980  5:44 PM

; Pup Checksum instruction
; 	AC0/ 0 initially
; 	AC1/ address of block
; 	AC3/ length of block (words)
; Computes the ones-complement add-and-cycle checksum over the block.
; When the instruction finishes,
; 	AC0/ result
; 	AC1/ address+length-1
; 	AC3/ 0
; This instruction is interruptible.  If an interrupt occurs, intermediate
; state is stored in the ACs and the PC is backed up so the instruction will
; start over when the interrupt is dismissed.
; Timing: 9 cycles/word
; 2484 cycles (= 422 microseconds) per maximum-length Pup

$AC3	$R0;
$AC1	$R2;
$AC0	$R3;
$NWW	$R4;
$PC	$R6;
$LREG	$R40;

!1,2,PCMayI,PCNoI;
!1,2,PCDoI,PCDisI;
!1,2,PCNoCy,PCCy;
!1,2,PCLoop,PCDone;
!1,2,PCNoMZ,PCMinZ;

PupChecksum:
	MAR← L← AC1, :PCLp1;	Start fetch of first word

; Top of main loop
PCLoop:	MAR← L← AC1+1;		Start fetch of next word
PCLp1:	AC1← L;			Update pointer
	L← NWW, BUS=0;		Test for interrupts
	T← AC0, SH<0, :PCMayI;	[PCMayI, PCNoI] Get accumulated checksum
PCMayI:	L← MD+T, :PCDoI;	[PCDoI, PCDisI] Add new word
PCNoI:	L← MD+T, :PCDisI;
PCDisI:	T← M, ALUCY;		Test for carry out
	L← AC3-1, :PCNoCy;	[PCNoCy, PCCy] Decrement and test count
PCNoCy:	AC3← L, L← T, SH=0, TASK, :PCLast;  No carry
PCCy:	AC3← L, L← T← 0+T+1, SH=0, TASK;  Do end-around carry
PCLast:	AC0← L MLSH 1, :PCLoop;	[PCLoop, PCDone] Left cycle 1

; Here when done
PCDone:	L← AC0+1;		Test for minus zero (ones-complement)
	SH=0;
PCDn1:	SWMODE, :PCNoMZ;	[PCNoMZ, PCMinZ]
PCNoMZ:	:START;
PCMinZ:	AC0← L, :START;		Minus zero, change to plus zero

; Here when interrupted
PCDoI:	L← PC-1, TASK;		Back up PC
	PC← L, :PCDn1;