```; IfsPupChecksum.mu
; Copyright Xerox Corporation 1979, 1980

; Pup Checksum instruction
; 	AC0/ 0 initially
; 	AC3/ length of block (words)
; Computes the ones-complement add-and-cycle checksum over the block.
; When the instruction finishes,
; 	AC0/ result
; 	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;
```