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