added math.crc16() and math.crc32()

This commit is contained in:
Irmen de Jong 2023-12-29 07:00:14 +01:00
parent 779a5606a7
commit 01bd648cb2
12 changed files with 130 additions and 275 deletions

View File

@ -484,4 +484,49 @@ log2_tab
}}
}
sub crc16(uword data, uword length) -> uword {
; calculates the CRC16 (XMODEM) checksum of the buffer.
cx16.r1 = data ; make sure pointer is in zp (on cx16)
cx16.r0 = 0 ; the crc value
repeat length {
cx16.r0H ^= @(cx16.r1)
repeat 8 {
if cx16.r0H & $80 {
cx16.r0 <<= 1
cx16.r0 ^= $1021
}
else
cx16.r0<<=1
}
cx16.r1++
}
return cx16.r0
}
sub crc32(uword data, uword length) {
; 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.
; result stored in cx16.r0 (low word) and cx16.r1 (high word)
cx16.r2 = data ; make sure pointer is in zp (on cx16)
cx16.r1 = 0
cx16.r0 = 0
repeat length {
cx16.r1H ^= @(cx16.r2)
repeat 8 {
if cx16.r1H & $80 {
cx16.r0 <<= 1
rol(cx16.r1)
cx16.r1 ^= $04c1
cx16.r0 ^= $1db7
}
else {
cx16.r0 <<= 1
rol(cx16.r1)
}
}
cx16.r2++
}
cx16.r1 ^= $ffff
cx16.r0 ^= $ffff
}
}

View File

@ -293,4 +293,45 @@ math {
return w2-w1
}
sub crc16(uword data, uword length) -> uword {
; calculates the CRC16 (XMODEM) checksum of the buffer.
cx16.r0 = 0 ; the crc value
repeat length {
cx16.r0H ^= @(data)
repeat 8 {
if cx16.r0H & $80
cx16.r0 = (cx16.r0<<1)^$1021
else
cx16.r0<<=1
}
data++
}
return cx16.r0
}
sub crc32(uword data, uword length) {
; 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.
; result stored in cx16.r0 (low word) and cx16.r1 (high word)
cx16.r1 = 0
cx16.r0 = 0
repeat length {
cx16.r1H ^= @(data)
repeat 8 {
if cx16.r1H & $80 {
cx16.r0 <<= 1
rol(cx16.r1)
cx16.r1 ^= $04c1
cx16.r0 ^= $1db7
}
else {
cx16.r0 <<= 1
rol(cx16.r1)
}
}
data++
}
cx16.r1 ^= $ffff
cx16.r0 ^= $ffff
}
}

View File

@ -491,6 +491,15 @@ but perhaps the provided ones can be of service too.
It does not work for the verafx multiplication routines on the Commander X16!
These have a different way to obtain the upper 16 bits of the result: just read cx16.r0.
``crc16 (uword data, uword length) -> uword``
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().
That one is faster, but yields different results. It is unclear what flavour of crc it is calculating.
``crc32 (uword data, uword length)``
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).
cx16logo
--------

View File

@ -2,8 +2,6 @@
TODO
====
- add crc8 and crc16 and crc32 to math
- fix crc* bench routines to no longer depend on the kernal rom version (use a bin file)
- make internalCast() not complain anymore about signed <-> unsigned conversions
- fix bitshift.p8

View File

@ -1,32 +0,0 @@
%import textio
%import floats
main {
sub crc16(uword data, uword length) -> uword {
uword crc = 0
repeat length {
crc ^= mkword(@(data), 0)
repeat 8 {
if crc & $8000
crc = (crc<<1)^$1021
else
crc<<=1
}
data++
}
return crc
}
sub start() {
txt.print("calculating (expecting $ffd0)...\n")
txt.print(" if mismatch: first check if kernal is maybe updated?\n")
cbm.SETTIM(0,0,0)
uword crc = crc16($e000, $2000)
txt.print_uwhex(crc, true)
txt.nl()
floats.print(cbm.RDTIM16() / 60.0)
txt.print(" seconds")
sys.wait(9999)
}
}

View File

@ -1,44 +0,0 @@
%import textio
%import floats
main {
sub crc32(uword data, uword length) {
; because prog8 doesn't have 32 bits integers, we have to split up the calucation over 2 words.
; result in cx16.r0 (high word) and cx1.r1 (low word).
cx16.r0 = 0
cx16.r1 = 0
repeat length {
cx16.r0 ^= mkword(@(data), 0)
repeat 8 {
if cx16.r0 & $8000 {
sys.clear_carry()
rol(cx16.r1)
rol(cx16.r0)
cx16.r0 ^= $04c1
cx16.r1 ^= $1db7
}
else {
sys.clear_carry()
rol(cx16.r1)
rol(cx16.r0)
}
}
data++
}
cx16.r0 ^= $ffff
cx16.r1 ^= $ffff
}
sub start() {
txt.print("calculating (expecting $e1fa84c6)...\n")
txt.print(" if mismatch: first check if kernal is maybe updated?\n")
cbm.SETTIM(0,0,0)
crc32($e000, $2000)
txt.print_uwhex(cx16.r0, true)
txt.print_uwhex(cx16.r1, false)
txt.nl()
floats.print(cbm.RDTIM16() / 60.0)
txt.print(" seconds")
sys.wait(9999)
}
}

View File

@ -1,32 +0,0 @@
%import textio
%import floats
main {
sub crc8(uword data, uword length) -> ubyte {
ubyte crc = 0
repeat length {
crc ^= @(data)
repeat 8 {
if crc & $80
crc = (crc<<1)^$1d
else
crc<<=1
}
data++
}
return crc
}
sub start() {
txt.print("calculating (expecting $a2)...\n")
txt.print(" if mismatch: first check if kernal is maybe updated?\n")
cbm.SETTIM(0,0,0)
ubyte crc = crc8($e000, $2000)
txt.print_ubhex(crc, true)
txt.nl()
floats.print(cbm.RDTIM16() / 60.0)
txt.print(" seconds")
sys.wait(9999)
}
}

View File

@ -1,42 +0,0 @@
%import textio
%import floats
main {
const ubyte N_ITER = 10
const ubyte SIZE = 32
float[SIZE] array = 0.0
sub testpow(float x, uword y) -> float {
float tmp = x
if y==0
return 1
repeat y-1 {
tmp *= x
}
return tmp
}
sub start() {
txt.print("calculating (expecting 3.614007e+12)...\n")
cbm.SETTIM(0,0,0)
float res=0.0
uword i
ubyte j
for i in 0 to N_ITER-1 {
for j in 0 to SIZE-1 {
array[j] += testpow(2.5/(i+1.0), j)
}
}
for j in 0 to SIZE-1 {
res += array[j]
}
floats.print(res)
txt.nl()
floats.print(cbm.RDTIM16() / 60.0)
txt.print(" seconds")
sys.wait(9999)
}
}

View File

@ -1 +0,0 @@
Contains several benchmarks from https://gglabs.us/node/2293 ported to prog8.

View File

@ -1,64 +0,0 @@
%import textio
%import floats
main {
const ubyte N_ITER = 4
const uword SIZE = 16000
uword @zp flags_ptr = memory("flags", SIZE/8+1, $100)
ubyte[] bitv = [ $01, $02, $04, $08, $10, $20, $40, $80 ]
sub start() {
txt.print_ub(N_ITER)
txt.print(" iterations, calculating... (expecting 3431)\n")
cbm.SETTIM(0, 0, 0)
uword prime_count
repeat N_ITER {
prime_count = sieve()
}
txt.print_uw(prime_count)
txt.print(" primes\n")
float time = cbm.RDTIM16() as float / 60.0
floats.print(time)
txt.print(" sec total = ")
floats.print(time/N_ITER)
txt.print(" sec per iteration\n")
sys.wait(9999)
}
sub check_flag(uword idx) -> ubyte
{
return flags_ptr[idx/8] & bitv[lsb(idx)&7]
}
sub clear_flag(uword idx)
{
flags_ptr[idx/8] &= ~bitv[lsb(idx)&7]
}
sub sieve() -> uword {
uword prime
uword k
uword count=0
uword i
sys.memset(flags_ptr, SIZE/8+1, $ff)
for i in 0 to SIZE-1 {
if check_flag(i) {
prime = i*2 + 3
k = i + prime
while k < SIZE {
clear_flag(k)
k += prime
}
; txt.print_uw(prime)
; txt.spc()
count++
}
}
return count
}
}

View File

@ -1,52 +0,0 @@
%import textio
%import floats
; The "Byte Sieve" test. https://en.wikipedia.org/wiki/Byte_Sieve
; Note: this program can be compiled for multiple target systems.
main {
sub start() {
const ubyte ITERS = 10
uword count
uword i
uword prime
uword k
const uword SIZEPL = 8191
uword @zp flags_ptr = memory("flags", SIZEPL, $100)
txt.print_ub(ITERS)
txt.print(" iterations, calculating...\n")
cbm.SETTIM(0, 0, 0)
repeat ITERS {
sys.memset(flags_ptr, SIZEPL, 1)
count = 0
for i in 0 to SIZEPL-1 {
if flags_ptr[i] {
prime = i*2 + 3
k = i + prime
while k < SIZEPL {
flags_ptr[k] = false
k += prime
}
; txt.print_uw(prime)
; txt.spc()
count++
}
}
}
txt.print_uw(count)
txt.print(" primes\n")
float time = cbm.RDTIM16() as float / 60.0
floats.print(time)
txt.print(" sec total = ")
floats.print(time/ITERS)
txt.print(" sec per iteration\n")
sys.wait(9999)
}
}

View File

@ -1,12 +1,41 @@
%import floats
%import math
%import string
%zeropage basicsafe
%import textio
%zeropage dontuse
main {
sub start() {
float fl = 1.2 ; no other assignments
cx16.r0L = string.isdigit(math.diff(119, floats.floor(floats.deg(fl)) as ubyte))
cx16.r1L = string.isletter(math.diff(119, floats.floor(floats.deg(1.2)) as ubyte))
str poem_data = iso:"Once upon a midnight dreary, while I pondered, weak and weary,"+
iso:"Over many a quaint and curious volume of forgotten lore-"+
iso:"While I nodded, nearly napping, suddenly there came a tapping,"+
iso:"As of some one gently rapping, rapping at my chamber door. ..."
uword size = len(poem_data)
cbm.SETTIM(0,0,0)
repeat 20 {
cx16.r9 = math.crc16(poem_data, size)
}
txt.print_uwhex(cx16.r9, true)
txt.spc()
txt.print_uw(cbm.RDTIM16())
txt.nl()
cbm.SETTIM(0,0,0)
repeat 20 {
cx16.r9 = cx16.memory_crc(poem_data, size) ; faster but I can't figure out the flavour of crc algorithm it uses, it's not any on https://crccalc.com/
}
txt.print_uwhex(cx16.r9, true)
txt.spc()
txt.print_uw(cbm.RDTIM16())
txt.nl()
cbm.SETTIM(0,0,0)
repeat 20 {
math.crc32(poem_data, size)
}
txt.print_uwhex(cx16.r1, true)
txt.print_uwhex(cx16.r0, false)
txt.spc()
txt.print_uw(cbm.RDTIM16())
txt.nl()
}
}