10 REM > CRC32
   20 REM CRC32 test code
   30 :
   40 DIM mem% &FFF:OSCLI"LOAD CRCs/htm "+STR$~mem%:num%=&A6D
   50 REM mem%=PAGE:num%=TOP-PAGE
   60 :
   70 @%=&90A
   80 PRINT"BASIC CRC-32:   ";:S%=-1:T%=TIME:PROCcrc:T%=TIME-T%:S%=NOT S%
   90 PRINT"&";~S%;" in ";T%/100;"s"'
  100 :
  110 @%=&2040A
  120 PROCAsm1
  130 PRINTA$;" CRC-32: ";:T%=TIME:FOR L%=1 TO N%:S%=-1:PROCcrcAsm:NEXT:T%=TIME-T%:S%=NOT S%
  140 PRINTSPC(7-LENA$)"&";~S%;" in ";T%/100/N%;"s"'
  150 :
  160 PROCAsm2
  170 PRINTA$;" CRC-32: ";:T%=TIME:FOR L%=1 TO N%:S%=-1:PROCcrcAsm:NEXT:T%=TIME-T%:S%=NOT S%
  180 PRINTSPC(7-LENA$)"&";~S%;" in ";T%/100/N%;"s"'
  190 END
  200 :
  210 DEFPROCcopy
  220 S%=-1                            :REM CRC starts as &FFFFFFFF
  230 REPEAT
  240     num%=EXT#in%-PTR#in%           :REM Number of bytes to transfer
  250     IF num%>max% THEN num%=max%
  260     PROCgbpb(rd%,in%,mem%,num%,0)  :REM Read block of data
  270     PROCcrc                        :REM Update CRC
  280     PROCgbpb(wr%,out%,mem%,num%,0) :REM Write block of data
  290 UNTIL num%<max%                  :REM Loop until all done
  300 crc%=NOT S%                      :REM Final CRC is inverted
  310 ENDPROC
  320 :
  330 REM BASIC:
  340 DEFPROCcrc:FORA%=mem%TOmem%+num%-1:S%=S%EOR?A%:FORB%=1TO8:O%=S%:S%=(((S%+(S%<0))DIV2)AND&7FFFFFFF):IFO%AND1:S%=S%EOR&EDB88320
  350 NEXT:NEXT:ENDPROC
  360 :
  370 REM Assembler:
  380 DEFPROCcrcAsm:!addr=mem%:!num=num%:!crc=S%:CALL Calc:S%=!crc:ENDPROC
  390 :
  400 REM With CRC-32 code previously assembled with:
  410 DEFPROCAsm1
  420 IFPAGE>&8000:IFINKEY-256=ASC"W":PROCcrc86:A$="80x86":N%=100:ENDPROC
  430 IFPAGE>&8000:PROCcrcARM:A$="ARM":N%=10:ENDPROC
  440 IF?&FFF7=&6C:PROCcrc65v1:A$="6502 v1":N%=1:ENDPROC
  450 IF?&FFF7=&C3:PROCcrc80:A$="Z80":N%=1:ENDPROC
  460 ENDPROC
  470 :
  480 DEFPROCAsm2
  490 IFPAGE>&8000:END
  500 IF?&FFF7=&6C:PROCcrc65v2:A$="6502 v2":N%=1:ENDPROC
  510 END
  520 ENDPROC
  530 :
  540 DEFPROCcrc65v2:DIM Calcv2 63:addr=&70:num=&72:crc=&74:FORP=0TO1
  550   P%=Calc:[OPT P*2
  560   .bytelp
  570   LDX #8                       :\ Prepare to rotate CRC 8 bits
  580   LDA (addr-8 AND &FF,X)       :\ Fetch byte from memory
  590   :
  600   \ The following code updates the CRC with the byte in A ---------+
  610   \ If used in isolation, requires LDX #8 here                     |
  620   EOR crc+0                    :\ EOR byte into CRC bottom byte    |
  630   .rotlp                       :\                                  |
  640   LSR crc+3:ROR crc+2          :\ Rotate CRC clearing bit 31       |
  650   ROR crc+1:ROR A              :\                                  |
  660   BCC clear                    :\ b0 was zero                      |
  670   TAY                          :\ Hold CRC low byte in Y           |
  680   LDA crc+3:EOR #&ED:STA crc+3 :\ CRC=CRC EOR &EDB88320, ZIP polynomic
  690   LDA crc+2:EOR #&B8:STA crc+2 :\                                  |
  700   LDA crc+1:EOR #&83:STA crc+1 :\                                  |
  710   TYA:EOR #&20                 :\ Get CRC low byte back from Y     |
  720   .clear                       :\                                  |
  730   DEX:BNE rotlp                :\ Loop for 8 bits                  |
  740   \ If used in isolation, requires STA crc+0 here                  |
  750   \ ---------------------------------------------------------------+
  760   :
  770   INC addr:BNE next:INC addr+1 :\ Step to next byte
  780   .next
  790   STA crc+0                    :\ Store CRC bottom byte
  800   :
  810   \ Now do a 16-bit decrement
  820   LDA num+0:BNE skip           :\ num.lo<>0, not wrapping from 00 to FF
  830   DEC num+1                    :\ Wrapping from 00 to FF, dec. high byte
  840   .skip
  850   DEC num+0:BNE bytelp         :\ Dec. low byte, loop until num.lo=0
  860   LDA num+1:BNE bytelp         :\ Loop until num=0
  870   RTS
  880 ]:NEXT:ENDPROC
  890 :
  900 DEFPROCcrc65v1:DIM Calc 79:addr=&70:num=&72:crc=&74:FORP=0TO1
  910   P%=Calc:[OPT P*2
  920   LDY #0                       :\ Point to first byte
  930   .bytelp
  940   LDA (addr),Y:EOR crc:STA crc :\ EOR byte into CRC bottom byte
  950   LDX #8                       :\ Prepare to rotate CRC 8 bits
  960   .rotlp
  970   LSR crc+3:ROR crc+2          :\ Rotate CRC
  980   ROR crc+1:ROR crc+0
  990   BCC clear                    :\ b0 was zero
 1000   LDA crc+3:EOR #&ED:STA crc+3 :\ CRC=CRC EOR &EDB88320, ZIP polynomic
 1010   LDA crc+2:EOR #&B8:STA crc+2
 1020   LDA crc+1:EOR #&83:STA crc+1
 1030   LDA crc+0:EOR #&20:STA crc+0
 1040   .clear
 1050   DEX:BNE rotlp                :\ Loop for 8 bits
 1060   INY:BNE next:INC addr+1      :\ Step to next byte
 1070   .next
 1080   SEC
 1090   LDA num+0:SBC #1:STA num+0   :\ num=num-1
 1100   LDA num+1:SBC #0:STA num+1
 1110   ORA num:BNE bytelp           :\ Loop until num=0
 1120   RTS
 1130 ]:NEXT:ENDPROC
 1140 :
 1150 DEFPROCcrc80:DIM Calc 79:addr=&70:num=&72:crc=&74:FORP=0TO1
 1160   P%=Calc:[OPT P*2
 1170   LD IX,(addr):LD BC,(num)  :\ Address, Count
 1180   LD DE,(crc):LD HL,(crc+2) :\ Incoming CRC
 1190   :
 1200   \ Enter here with IX=>data, BC=count, HLDE=incoming CRC
 1210   .bytelp
 1220   PUSH BC                   :\ Save count
 1230   LD A,(IX)                 :\ Fetch byte from memory
 1240   :
 1250   \ The following code updates the CRC with the byte in A ---------+
 1260   XOR E                     :\ XOR byte into CRC bottom byte       |
 1270   LD B,8                    :\ Prepare to rotate 8 bits            |
 1280   .rotlp                    :\                                     |
 1290   SRL H:RR L:RR D:RRA       :\ Rotate CRC                          |
 1300   JP NC,clear               :\ b0 was zero                         |
 1310   LD E,A                    :\ Put CRC low byte back into E        |
 1320   LD A,H:XOR &ED:LD H,A     :\ CRC=CRC XOR &EDB88320, ZIP polynomic|
 1330   LD A,L:XOR &B8:LD L,A     :\                                     |
 1340   LD A,D:XOR &83:LD D,A     :\                                     |
 1350   LD A,E:XOR &20            :\ And get CRC low byte back into A    |
 1360   .clear                    :\                                     |
 1370   DEC B:JP NZ,rotlp         :\ Loop for 8 bits                     |
 1380   LD E,A                    :\ Put CRC low byte back into E        |
 1390   \ ---------------------------------------------------------------+
 1400   :
 1410   INC IX                    :\ Step to next byte
 1420   POP BC:DEC BC             :\ num=num-1
 1430   LD A,B:OR C:JP NZ,bytelp  :\ Loop until num=0
 1440   LD (crc),DE:LD (crc+2),HL :\ Store outgoing CRC
 1450   RET
 1460 ]:NEXT:PRINTP%-Calc:ENDPROC
 1470 :
 1480 DEFPROCcrcARM:DIM Calc 79:FORP=0TO1
 1490   P%=Calc:[OPT P*2
 1500   LDR R0,addr:LDR R1,num    :\ Address, Count
 1510   LDR R2,crc                :\ Incoming CRC
 1520   \
 1530   \ Enter here with R0=addr, R1=num, R2=crc
 1540   \
 1550   .crc32reg
 1560   LDR R3,xor                :\ ZIP polynomic
 1570   .bytelp
 1580   LDRB R4,[R0],#1           :\ Get byte, inc address
 1590   :
 1600   \ The following code updates the CRC with the byte in R4 --------+
 1610   \ If used in isolation, requires LDR R3,xor here                 |
 1620   EOR R2,R2,R4              :\ EOR byte into CRC bottom byte       |
 1630   MOV R4,#8                 :\ Prepare to rotate 8 bits            |
 1640   .rotlp                    :\                                     |
 1650   MOVS R2,R2,LSR #1         :\ Rotate CRC                          |
 1660   EORCS R2,R2,R3            :\ If b0 was set, EOR with ZIP polynomic
 1670   SUBS R4,R4,#1:BNE rotlp   :\ Loop for 8 bits                     |
 1680   \ ---------------------------------------------------------------+
 1690   :
 1700   SUBS R1,R1,#1:BNE bytelp  :\ Loop until num=0
 1710   STR R2,crc:MOV R15,R14    :\ Store outgoing CRC and return
 1720   .xor:EQUD &EDB88320       :\ ZIP polynomic
 1730   .addr:EQUD 0:.num:EQUD 0
 1740   .crc:EQUD 0
 1750 ]:NEXT:ENDPROC
 1760 :
 1770 DEFPROCcrc86:DIM Calc 63:FORP=0TO1
 1780   P%=Calc:[OPT P*2
 1790   .crc32
 1800   MOV ESI,[addr]      ; ESI=>start of data
 1810   MOV EBX,[num]       ; EBX= length of data
 1820   MOV ECX,[crc]       ; ECX= incoming CRC
 1830   ;
 1840   .bytelp
 1850   MOV AL,[ESI]        ; Fetch byte from memory
 1860   ;
 1870   ; The following code updates the CRC with the byte in AL -----+
 1880   XOR CL,AL           ; XOR byte into bottom of CRC             |
 1890   MOV AL,8            ; Prepare to rotate 8 bits                |
 1900   .rotlp              ;                                         |
 1910   SHR ECX,1           ; Rotate CRC                              |
 1920   JNC clear           ; b0 was zero                             |
 1930   XOR ECX,&EDB88320   ; If b0 was set, XOR with ZIP polymonic   |
 1940   .clear              ;                                         |
 1950   DEC AL:JNZ rotlp    ; Loop for 8 bits                         |
 1960   ; ------------------------------------------------------------+
 1970   ;
 1980   INC SI              ; Point to next byte
 1990   DEC EBX:JNE bytelp  ; num=num-1, loop until num=0
 2000   MOV [crc],ECX       ; Store outgoing CRC
 2010   RETF
 2020   .addr:DD 0
 2030   .num:DD 0
 2040   .crc:DD 0
 2050 ]:NEXT:ENDPROC
 2060 :