mirror of
https://github.com/irmen/prog8.git
synced 2025-02-09 07:31:34 +00:00
optimized and added "streaming" crc32 and crc16 routines to math module. Return value is put in different register now! r14+r15 instead of r0+r1!
This commit is contained in:
parent
6a9269111e
commit
fbe231793b
@ -504,47 +504,137 @@ log2_tab
|
|||||||
|
|
||||||
sub crc16(uword data, uword length) -> uword {
|
sub crc16(uword data, uword length) -> uword {
|
||||||
; calculates the CRC16 (XMODEM) checksum of the buffer.
|
; calculates the CRC16 (XMODEM) checksum of the buffer.
|
||||||
cx16.r1 = data ; make sure pointer is in zp (on cx16)
|
; There are also "streaming" crc16_start/update/end routines below, that allow you to calculate crc16 for data that doesn't fit in a single memory block.
|
||||||
cx16.r0 = 0 ; the crc value
|
crc16_start()
|
||||||
repeat length {
|
cx16.r13 = data
|
||||||
cx16.r0H ^= @(cx16.r1)
|
cx16.r14 = data+length
|
||||||
repeat 8 {
|
while cx16.r13!=cx16.r14 {
|
||||||
if cx16.r0H & $80 !=0 {
|
crc16_update(@(cx16.r13))
|
||||||
cx16.r0 <<= 1
|
cx16.r13++
|
||||||
cx16.r0 ^= $1021
|
|
||||||
}
|
|
||||||
else
|
|
||||||
cx16.r0<<=1
|
|
||||||
}
|
|
||||||
cx16.r1++
|
|
||||||
}
|
}
|
||||||
return cx16.r0
|
return crc16_end()
|
||||||
|
}
|
||||||
|
|
||||||
|
sub crc16_start() {
|
||||||
|
; start the "streaming" crc16
|
||||||
|
; note: tracks the crc16 checksum in cx16.r15!
|
||||||
|
; if your code uses that, it must save/restore it before calling this routine
|
||||||
|
cx16.r15 = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
asmsub crc16_update(ubyte value @A) {
|
||||||
|
; update the "streaming" crc16 with next byte value
|
||||||
|
; note: tracks the crc16 checksum in cx16.r15!
|
||||||
|
; if your code uses that, it must save/restore it before calling this routine
|
||||||
|
%asm {{
|
||||||
|
eor cx16.r15H
|
||||||
|
sta cx16.r15H
|
||||||
|
ldy #8
|
||||||
|
- lda cx16.r15H
|
||||||
|
asl cx16.r15L
|
||||||
|
rol cx16.r15H
|
||||||
|
and #$80
|
||||||
|
beq +
|
||||||
|
lda cx16.r15H
|
||||||
|
eor #$10
|
||||||
|
sta cx16.r15H
|
||||||
|
lda cx16.r15L
|
||||||
|
eor #$21
|
||||||
|
sta cx16.r15L
|
||||||
|
+ dey
|
||||||
|
bne -
|
||||||
|
rts
|
||||||
|
}}
|
||||||
|
; orignal prog8 code was:
|
||||||
|
; cx16.r15H ^= value
|
||||||
|
; repeat 8 {
|
||||||
|
; if cx16.r15H & $80 !=0 {
|
||||||
|
; cx16.r15 <<=1
|
||||||
|
; cx16.r15 ^= $1021
|
||||||
|
; } else
|
||||||
|
; cx16.r15<<=1
|
||||||
|
; }
|
||||||
|
}
|
||||||
|
|
||||||
|
sub crc16_end() -> uword {
|
||||||
|
; finalize the "streaming" crc16, returns resulting crc16 value
|
||||||
|
return cx16.r15
|
||||||
}
|
}
|
||||||
|
|
||||||
sub crc32(uword data, uword length) {
|
sub crc32(uword data, uword length) {
|
||||||
; Calculates the CRC-32 (POSIX) checksum of the buffer.
|
; Calculates the CRC-32 (POSIX) checksum of the buffer.
|
||||||
; because prog8 doesn't have 32 bits integers, we have to split up the calculation over 2 words.
|
; because prog8 doesn't have 32 bits integers, we have to split up the calculation over 2 words.
|
||||||
; result stored in cx16.r0 (low word) and cx16.r1 (high word)
|
; result stored in cx16.r14 (low word) and cx16.r15 (high word)
|
||||||
cx16.r2 = data ; make sure pointer is in zp (on cx16)
|
; There are also "streaming" crc32_start/update/end routines below, that allow you to calculate crc32 for data that doesn't fit in a single memory block.
|
||||||
cx16.r1 = 0
|
crc32_start()
|
||||||
cx16.r0 = 0
|
cx16.r12 = data
|
||||||
repeat length {
|
cx16.r13 = data+length
|
||||||
cx16.r1H ^= @(cx16.r2)
|
while cx16.r12!=cx16.r13 {
|
||||||
repeat 8 {
|
crc32_update(@(cx16.r12))
|
||||||
if cx16.r1H & $80 !=0 {
|
cx16.r12++
|
||||||
cx16.r0 <<= 1
|
|
||||||
rol(cx16.r1)
|
|
||||||
cx16.r1 ^= $04c1
|
|
||||||
cx16.r0 ^= $1db7
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
cx16.r0 <<= 1
|
|
||||||
rol(cx16.r1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cx16.r2++
|
|
||||||
}
|
}
|
||||||
cx16.r1 ^= $ffff
|
crc32_end()
|
||||||
cx16.r0 ^= $ffff
|
}
|
||||||
|
|
||||||
|
sub crc32_start() {
|
||||||
|
; start the "streaming" crc32
|
||||||
|
; note: tracks the crc32 checksum in cx16.r14 and cx16.r15!
|
||||||
|
; if your code uses these, it must save/restore them before calling this routine
|
||||||
|
cx16.r14 = cx16.r15 = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
asmsub crc32_update(ubyte value @A) {
|
||||||
|
; update the "streaming" crc32 with next byte value
|
||||||
|
; note: tracks the crc32 checksum in cx16.r14 and cx16.r15!
|
||||||
|
; if your code uses these, it must save/restore them before calling this routine
|
||||||
|
%asm {{
|
||||||
|
eor cx16.r15H
|
||||||
|
sta cx16.r15H
|
||||||
|
ldy #8
|
||||||
|
- lda cx16.r15H
|
||||||
|
asl cx16.r14L
|
||||||
|
rol cx16.r14H
|
||||||
|
rol cx16.r15L
|
||||||
|
rol cx16.r15H
|
||||||
|
and #$80
|
||||||
|
beq +
|
||||||
|
lda cx16.r15H
|
||||||
|
eor #$04
|
||||||
|
sta cx16.r15H
|
||||||
|
lda cx16.r15L
|
||||||
|
eor #$c1
|
||||||
|
sta cx16.r15L
|
||||||
|
lda cx16.r14H
|
||||||
|
eor #$1d
|
||||||
|
sta cx16.r14H
|
||||||
|
lda cx16.r14L
|
||||||
|
eor #$b7
|
||||||
|
sta cx16.r14L
|
||||||
|
+ dey
|
||||||
|
bne -
|
||||||
|
rts
|
||||||
|
}}
|
||||||
|
; original prog8 code:
|
||||||
|
; cx16.r15H ^= value
|
||||||
|
; repeat 8 {
|
||||||
|
; if cx16.r15H & $80 !=0 {
|
||||||
|
; cx16.r14 <<= 1
|
||||||
|
; rol(cx16.r15)
|
||||||
|
; cx16.r15 ^= $04c1
|
||||||
|
; cx16.r14 ^= $1db7
|
||||||
|
; }
|
||||||
|
; else {
|
||||||
|
; cx16.r14 <<= 1
|
||||||
|
; rol(cx16.r15)
|
||||||
|
; }
|
||||||
|
; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub crc32_end() {
|
||||||
|
; finalize the "streaming" crc32
|
||||||
|
; result stored in cx16.r14 (low word) and cx16.r15 (high word)
|
||||||
|
cx16.r15 ^= $ffff
|
||||||
|
cx16.r14 ^= $ffff
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,43 +313,87 @@ math {
|
|||||||
|
|
||||||
sub crc16(uword data, uword length) -> uword {
|
sub crc16(uword data, uword length) -> uword {
|
||||||
; calculates the CRC16 (XMODEM) checksum of the buffer.
|
; calculates the CRC16 (XMODEM) checksum of the buffer.
|
||||||
cx16.r0 = 0 ; the crc value
|
; There are also "streaming" crc16_start/update/end routines below, that allow you to calculate crc32 for data that doesn't fit in a single memory block.
|
||||||
repeat length {
|
crc16_start()
|
||||||
cx16.r0H ^= @(data)
|
cx16.r13 = data
|
||||||
repeat 8 {
|
cx16.r14 = data+length
|
||||||
if cx16.r0H & $80 !=0
|
while cx16.r13!=cx16.r14 {
|
||||||
cx16.r0 = (cx16.r0<<1)^$1021
|
crc16_update(@(cx16.r13))
|
||||||
else
|
cx16.r13++
|
||||||
cx16.r0<<=1
|
|
||||||
}
|
|
||||||
data++
|
|
||||||
}
|
}
|
||||||
return cx16.r0
|
return crc16_end()
|
||||||
|
}
|
||||||
|
|
||||||
|
sub crc16_start() {
|
||||||
|
; start the "streaming" crc16
|
||||||
|
; note: tracks the crc16 checksum in cx16.r15!
|
||||||
|
; if your code uses that, it must save/restore it before calling this routine
|
||||||
|
cx16.r15 = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
sub crc16_update(ubyte value) {
|
||||||
|
; update the "streaming" crc16 with next byte value
|
||||||
|
; note: tracks the crc16 checksum in cx16.r15!
|
||||||
|
; if your code uses that, it must save/restore it before calling this routine
|
||||||
|
cx16.r15H ^= value
|
||||||
|
repeat 8 {
|
||||||
|
if cx16.r15H & $80 !=0
|
||||||
|
cx16.r15 = (cx16.r15<<1)^$1021
|
||||||
|
else
|
||||||
|
cx16.r15<<=1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub crc16_end() -> uword {
|
||||||
|
; finalize the "streaming" crc16, returns resulting crc16 value
|
||||||
|
return cx16.r15
|
||||||
}
|
}
|
||||||
|
|
||||||
sub crc32(uword data, uword length) {
|
sub crc32(uword data, uword length) {
|
||||||
; Calculates the CRC-32 (POSIX) checksum of the buffer.
|
; Calculates the CRC-32 (POSIX) checksum of the buffer.
|
||||||
; because prog8 doesn't have 32 bits integers, we have to split up the calculation over 2 words.
|
; because prog8 doesn't have 32 bits integers, we have to split up the calculation over 2 words.
|
||||||
; result stored in cx16.r0 (low word) and cx16.r1 (high word)
|
; result stored in cx16.r14 (low word) and cx16.r15 (high word)
|
||||||
cx16.r1 = 0
|
; There are also "streaming" crc32_start/update/end routines below, that allow you to calculate crc32 for data that doesn't fit in a single memory block.
|
||||||
cx16.r0 = 0
|
crc32_start()
|
||||||
repeat length {
|
cx16.r12 = data
|
||||||
cx16.r1H ^= @(data)
|
cx16.r13 = data+length
|
||||||
repeat 8 {
|
while cx16.r12!=cx16.r13 {
|
||||||
if cx16.r1H & $80 !=0 {
|
crc32_update(@(cx16.r12))
|
||||||
cx16.r0 <<= 1
|
cx16.r12++
|
||||||
rol(cx16.r1)
|
|
||||||
cx16.r1 ^= $04c1
|
|
||||||
cx16.r0 ^= $1db7
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
cx16.r0 <<= 1
|
|
||||||
rol(cx16.r1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
data++
|
|
||||||
}
|
}
|
||||||
cx16.r1 ^= $ffff
|
crc32_end()
|
||||||
cx16.r0 ^= $ffff
|
}
|
||||||
|
|
||||||
|
sub crc32_start() {
|
||||||
|
; start the "streaming" crc32
|
||||||
|
; note: tracks the crc32 checksum in cx16.r14 and cx16.r15!
|
||||||
|
; if your code uses these, it must save/restore them before calling this routine
|
||||||
|
cx16.r14 = cx16.r15 = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
sub crc32_update(ubyte value) {
|
||||||
|
; update the "streaming" crc32 with next byte value
|
||||||
|
; note: tracks the crc32 checksum in cx16.r14 and cx16.r15!
|
||||||
|
; if your code uses these, it must save/restore them before calling this routine
|
||||||
|
cx16.r15H ^= value
|
||||||
|
repeat 8 {
|
||||||
|
if cx16.r15H & $80 !=0 {
|
||||||
|
cx16.r14 <<= 1
|
||||||
|
rol(cx16.r15)
|
||||||
|
cx16.r15 ^= $04c1
|
||||||
|
cx16.r14 ^= $1db7
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cx16.r14 <<= 1
|
||||||
|
rol(cx16.r15)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub crc32_end() {
|
||||||
|
; finalize the "streaming" crc32
|
||||||
|
; result stored in cx16.r14 (low word) and cx16.r15 (high word)
|
||||||
|
cx16.r15 ^= $ffff
|
||||||
|
cx16.r14 ^= $ffff
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -532,12 +532,22 @@ but perhaps the provided ones can be of service too.
|
|||||||
``crc16 (uword data, uword length) -> uword``
|
``crc16 (uword data, uword length) -> uword``
|
||||||
Returns a CRC-16 (XMODEM) checksum over the given data buffer.
|
Returns a CRC-16 (XMODEM) checksum over the given data buffer.
|
||||||
Note: on the Commander X16, there is a CRC-16 routine in the kernal: cx16.memory_crc().
|
Note: on the Commander X16, there is a CRC-16 routine in the kernal: cx16.memory_crc().
|
||||||
That one is faster, but yields different results. It is unclear what flavour of crc it is calculating.
|
That one is faster, but yields different results. It is unclear to me what flavour of crc it is calculating.
|
||||||
|
|
||||||
|
``crc16_start() / crc16_update(ubyte value) / crc16_end() -> uword``
|
||||||
|
"streaming" crc16 calculation routines, when the data doesn't fit in a single buffer.
|
||||||
|
Tracks the crc16 checksum in cx16.r15! If your code uses that, it must save/restore it before calling this routine!
|
||||||
|
Call the start() routine first, feed it bytes with the update() routine, finalize with calling the end() routine which returns the crc16 value.
|
||||||
|
|
||||||
``crc32 (uword data, uword length)``
|
``crc32 (uword data, uword length)``
|
||||||
Calculates a CRC-32 (POSIX) checksum over the given data buffer.
|
Calculates a CRC-32 (POSIX) checksum over the given data buffer.
|
||||||
The 32 bits result is stored in cx16.r0 (low word) and cx16.r1 (high word).
|
The 32 bits result is stored in cx16.r14 (low word) and cx16.r15 (high word).
|
||||||
|
|
||||||
|
``crc32_start() / crc32_update(ubyte value) / crc32_end()``
|
||||||
|
"streaming" crc32 calculation routines, when the data doesn't fit in a single buffer.
|
||||||
|
Tracks the crc32 checksum in cx16.r14 and cx16.r15! If your code uses these, it must save/restore them before calling this routine!
|
||||||
|
Call the start() routine first, feed it bytes with the update() routine, finalize with calling the end() routine.
|
||||||
|
The 32 bits result is stored in cx16.r14 (low word) and cx16.r15 (high word).
|
||||||
|
|
||||||
cx16logo
|
cx16logo
|
||||||
--------
|
--------
|
||||||
|
@ -24,8 +24,8 @@ main {
|
|||||||
large[cx16.r0] = math.rnd()
|
large[cx16.r0] = math.rnd()
|
||||||
}
|
}
|
||||||
math.crc32(large, 20000)
|
math.crc32(large, 20000)
|
||||||
uword crc32_l = cx16.r0
|
uword crc32_l = cx16.r14
|
||||||
uword crc32_h = cx16.r1
|
uword crc32_h = cx16.r15
|
||||||
}
|
}
|
||||||
|
|
||||||
txt.print("\n\x12diskio.save()\x92 writing 10*20kb=200kb total")
|
txt.print("\n\x12diskio.save()\x92 writing 10*20kb=200kb total")
|
||||||
@ -168,9 +168,9 @@ main {
|
|||||||
sub compare_crc32(uword ptr, uword size, uword crc32_low, uword crc32_high)
|
sub compare_crc32(uword ptr, uword size, uword crc32_low, uword crc32_high)
|
||||||
{
|
{
|
||||||
math.crc32(ptr, size)
|
math.crc32(ptr, size)
|
||||||
if cx16.r0!=crc32_low or cx16.r1!=crc32_high {
|
if cx16.r14!=crc32_low or cx16.r15!=crc32_high {
|
||||||
txt.print_uwhex(cx16.r1, true)
|
txt.print_uwhex(cx16.r15, true)
|
||||||
txt.print_uwhex(cx16.r0, false)
|
txt.print_uwhex(cx16.r14, false)
|
||||||
txt.nl()
|
txt.nl()
|
||||||
txt.print_uwhex(crc32_high, true)
|
txt.print_uwhex(crc32_high, true)
|
||||||
txt.print_uwhex(crc32_low, false)
|
txt.print_uwhex(crc32_low, false)
|
||||||
|
@ -1,27 +1,41 @@
|
|||||||
|
%import math
|
||||||
%import textio
|
%import textio
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
%option no_sysinit
|
%option no_sysinit
|
||||||
|
|
||||||
|
; $029f
|
||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
cx16.reset_system()
|
txt.print("crc16\n")
|
||||||
repeat {
|
txt.print_uwhex(math.crc16($0800, 32768), true)
|
||||||
for cx16.r0L in 0 to 255 {
|
txt.nl()
|
||||||
cx16.set_led_brightness(cx16.r0L)
|
|
||||||
delay()
|
|
||||||
}
|
|
||||||
for cx16.r0L in 255 downto 0 {
|
|
||||||
cx16.set_led_brightness(cx16.r0L)
|
|
||||||
delay()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub delay() {
|
cx16.r15 = 0
|
||||||
repeat 2000 {
|
math.crc16_start()
|
||||||
%asm {{
|
for cx16.r9 in $0800 to $0800+32768-1 {
|
||||||
nop
|
math.crc16_update(@(cx16.r9))
|
||||||
}}
|
|
||||||
}
|
}
|
||||||
|
txt.print_uwhex(math.crc16_end(), true)
|
||||||
|
txt.nl()
|
||||||
|
|
||||||
|
txt.print("crc32\n")
|
||||||
|
cx16.r0 = cx16.r1 = 0
|
||||||
|
math.crc32($0800, 32768)
|
||||||
|
txt.print_uwhex(cx16.r15, true)
|
||||||
|
txt.print_uwhex(cx16.r14, false)
|
||||||
|
txt.nl()
|
||||||
|
|
||||||
|
cx16.r0 = cx16.r1 = 0
|
||||||
|
math.crc32_start()
|
||||||
|
for cx16.r9 in $0800 to $0800+32768-1 {
|
||||||
|
math.crc32_update(@(cx16.r9))
|
||||||
|
}
|
||||||
|
math.crc32_end()
|
||||||
|
txt.print_uwhex(cx16.r15, true)
|
||||||
|
txt.print_uwhex(cx16.r14, false)
|
||||||
|
txt.nl()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user