I realized that I could do most of it in a single procedure without the use of asm.
It's not as fast and doesn't support CRC with a width above 32 bits but seems to work fine.
In it's current configuration, the result is the same as the PB builtin CRC32 algorithm.
Some other often used configurations ...
CRC-16/CCITT: Width=16, Poly=$1021, Init=$ffff, RefIn=#False, RefOut=#False, XOrOut=0
CRC-16/MODBUS: Width=16, Poly=$8005, Init=$ffff, RefIn=#True, RefOut=#True, XOrOut=0
For more of them, see http://reveng.sourceforge.net/crc-catalogue/
Code: Select all
Procedure.l CRC(*Buffer, Size)
Static.l Width = 32
Static.l Poly = $04c11db7
Static.l Init = -1
Static.l RefIn = #True
Static.l RefOut = #True
Static.l XOrOut = -1
Static.l M
Static Dim T.l(1023)
Protected.l i,j,C,R,*B1.Ascii,*B4.Long
; Calculate CRC lookup table
If Not M
M=~((-2)<<(Width-1))
If RefIn
R=0: For i=1 To Width: R|((Poly>>(i-1))&1)<<(Width-i): Next
Else
R=Poly<<(32-Width)
EndIf
For i=0 To 255
If RefIn
C=i: For j=0 To 7: C=((C>>1)&$7fffffff)!((-(C&1))&R): Next
Else
C=i<<24: For j=0 To 7: C=(C<<1)!((C>>31)&R): Next
C=(C<<24)|(((C>>8)&255)<<16)|(((C>>16)&255)<<8)|((C>>24)&255)
EndIf
T(i)=C
Next
For i=0 To 255
C=T(i): For j=1 To 3: C=((C>>8)&$ffffff)!T(C&255): T((j<<8)|i)=C: Next
Next
EndIf
; 4 byte loop
C=Init&M: *B4=*Buffer
While Size >= 4
C!*B4\l: *B4+4: Size-4
C=T(C&255+768)!T(((C>>8)&255)+512)!T(((C>>16)&255)+256)!T(((C>>24)&255))
Wend
; 1 byte loop
*B1=*B4
While Size
C=((C>>8)&$ffffff)!T((C!*B1\a)&255)
*B1+1: Size-1
Wend
; Finalize and output CRC
If Not RefIn
C=((C<<24)|(((C>>8)&255)<<16)|(((C>>16)&255)<<8)|((C>>24)&255))>>(32-Width)
EndIf
If RefOut<>RefIn
R=0: For i=1 To Width: R|((C>>(i-1))&1)<<(Width-i): Next: C=R
EndIf
ProcedureReturn (C!XOrOut)&M
EndProcedure