I do get a result that varies with different strings. But have a question down below...
Here's the setup I used (BASLOAD):
EDIT/NOTE: The following sample is revised from the original. The issue was found and the correction is now applied to this example. The issue was that the KERNAL CRC call operates "in reverse" for small data under 256 bytes, which all BASIC strings can be at most is 256 bytes. BASIC strings aren't restricted to ASCII/PETSCII sequences, and can any character value 0-255 (and other characteristics like a normal array).
Code: Select all
SAMPLE$=CHR$(1)+CHR$(2)+CHR$(3)+CHR$(4)
REM AS OF R48 IT WAS DETERMINED THAT THE KERNAL CRC CALCULATION
REM OPERATES "IN REVERSE" FOR DATA UNDER 256 BYTES. THEREFORE,
REM TO BE COMPATIBLE WITH EXTERNAL SYSTEMS THAT ARE UNAWARE OF THIS,
REM IT WOULD BE PRUDENT TO REVERSE THE STRING SO THAT THE KERNAL CRC
REM RESULT WILL BE CONSISTENT WITH THOSE EXTERNAL SYSTEMS.
REM ONE PROPOSED WAY TO REVERSE THE STRING:
SAMPLE.REVERSE$ = ""
FOR I = LEN(SAMPLE$) TO 1 STEP -1
SAMPLE.REVERSE$ = SAMPLE.REVERSE$ + MID$(SAMPLE$,I,1)
NEXT I
AD=POINTER(SAMPLE.REVERSE$)
STR.SZ=PEEK(AD) : REM SIZE(LENGTH) IS FIRST BYTE
STR.LO=PEEK(AD+1)
STR.HI=PEEK(AD+2)
STR.ADDR=(STR.HI*256)+STR.LO
PRINT "STR @ [";HEX$(STR.ADDR);"]",STR.SZ
FOR I = STR.ADDR TO STR.ADDR+(STR.SZ-1)
V = PEEK(I)
PRINT HEX$(V);" ";
NEXT I
PRINT
REM ---------------------
REG.R0.LO=$02
REG.R0.HI=$03
REG.R1.LO=$04
REG.R1.HI=$05
REG.R2.LO=$06
REG.R2.HI=$07
KERNAL.CRC = $FEEA
REM ---------------------
POKE REG.R0.HI, STR.HI
POKE REG.R0.LO, STR.LO
POKE REG.R1.HI, $00
POKE REG.R1.LO, 4 : REM STR.SZ : REM BASIC STRINGS LIMITED TO 256 BYTES MAX.
SYS $FEEA : REM KERNAL.CRC
CRC.HI = PEEK(REG.R2.HI)
CRC.LO = PEEK(REG.R2.LO)
CRC.VALUE = CRC.HI*256+CRC.LO
PRINT HEX$(CRC.VALUE)
Here's some notes from the call in the KERNAL code:
Code: Select all
;---------------------------------------------------------------
; memory_crc
;
; Function: Calculate the CRC16 of a memory region.
;
; Pass: r0 address
; r1 number of bytes
;
; Return: r2 CRC16 result
;---------------------------------------------------------------
memory_crc:
lda #$ff
sta r2L
sta r2H
.....
@4: rts
; This is taken from
; http://www.6502.org/source/integers/crc-more.html
; (November 23rd, 2004, "alternate ending" version, preserving .Y)
crc16_f:
eor r2H ; A contained the data
sta r2H ; XOR it into high byte
....
I went to the 6502.org reference link mentioned in the code. Spot checking the code, it does seem Steil followed that reference exactly (the alternate part that preserves Y). But in that reference, it has this note:
Code: Select all
With a starting CRC of $FFFF, the binary string $01 $02 $03 $04 should evaluate to $89C3.
EDIT: Tentatively, it looks like the KERNAL code is "seeding" the CRC with $FFFF ? Just based on the first few lines the LDA #$FF and storing those into R2 (which is the output register).
And, I have reason to believe the $89C3 might be correct, based on this site that does a bunch of variety of CRC16 results (it matches the old IBM3740 version). There are a bunch of different ways to do CRC16 (I mean constants to plugin), and I wanted to understand which variation the KERNAL is doing - which then from Python or C# or Java or something I'll need an equivalent CRC16 calculator {or write one}).