!iso4sum
! Checksum algorithm used in ISO Transport Protocol Version 1

%option "-low"

! %integerfn mod255 (%integer n)
!   %if n<0 %start
!     n = -n
!     n = n&255+n>>8 %while n>>8#0
!     n = n!!255 %unless n=0
!   %else
!     n = n&255+n>>8 %while n>>8#0
!     n = 0 %if n=255
!   %finish
!   %result = n
! %end

! Optimised:

%integerfn mod255 (%integer n)
%label neg,pr,mr,rr
  *tst.l d0
  *bmi neg
pl:*move.l d0,d1
  *lsr.l #8,d1
  *beq pr
  *and.l #255,d0
  *add.l d1,d0
  *bra pl
pr:*cmp.b #255,d0
  *bne rr
  *clr d0
  *bra rr
neg:*neg.l d0
ml:*move.l d0,d1
  *lsr.l #8,d1
  *beq mr
  *and.l #255,d0
  *add.l d1,d0
  *bra ml
mr:*tst.b d0
  *beq rr
  *not.b d0
rr:*rts
%end

! %routine generate sum (%bytename b,%integer l,n)
! !B is the first byte of a block to be summed.
! !The block is L bytes long.
! !The result of the calculation is to be stored
! !in the Nth and next byte of the block, assuming
! !that initially B is the 1st, not 0th byte.
! !%integer i,c0=0,c1=0
! !%bytename x,y
!   y == b[n]; x == y[-1]
!   x = 0; y = 0
!   %for i = 1,1,l %cycle
!     c0 = c0+b; c1 = c1+c0; b == b[1]
!   %repeat
!   c0 = mod255(c0); c1 = mod255(c1)
!   i = c0*(l-n)-c1
!   x = mod255(i)
!   i = c1-c0*(l-n+1)
!   y = mod255(i)
! %end

! Optimised:

%routine generate sum(%bytename b,%integer l,n)
  *lea 0(a0,d1.l),a2
  *lea -1(a2),a1
  *clr.b (a1)
  *clr.b (a2)
  *clr.l d2
  *clr.l d3
  *move.l d0,d4
  *move.l d1,-(sp)
  *clr.l d1
z:*move.b (a0)+,d1
  *add.l d1,d2
  *add.l d2,d3
  *subq.l #1,d0
  *bgt z
  *move.l d2,d0
  *jsr mod255
  *move.l d0,d2
  *move.l d3,d0
  *jsr mod255
  *move.l d0,d3
  *move.l d4,d0
  *sub.l (sp),d0
  *mulu d2,d0
  *sub.l d3,d0
  *jsr mod255
  *move.b d0,(a1)
  *move.l d4,d0
  *sub.l (sp)+,d0
  *addq.l #1,d0
  *mulu d2,d0
  *sub.l d3,d0
  *neg.l d0
  *jsr mod255
  *move.b d0,(a2)
  *clr.l d4
%end

! %predicate check sum (%bytename b,%integer l)
! %integer i,c0=0,c1=0
!   %for i = 1,1,l %cycle
!     c0 = c0+b; c1 = c1+c0; b == b[1]
!   %repeat
!   c0 = mod255(c0); c1 = mod255(c1)
!   %trueif c0!c1=0
!   %false
! %end

! Optimised:

%predicate check sum (%bytename b,%integer l)
%label true
  *clr.l d2
  *clr.l d3
  *clr.l d1
z:*move.b (a0)+,d1
  *add.l d1,d2
  *add.l d2,d3
  *subq.l #1,d0
  *bgt z
  *move.l d2,d0
  *jsr mod255
  *move.l d0,d2
  *move.l d3,d0
  *jsr mod255
  *or.b d2,d0
  *beq true
  *moveq #0,d0
  *rts
true:*moveq #1,d0
%end

