diff --git a/compiler/res/prog8lib/math.p8 b/compiler/res/prog8lib/math.p8 index 086faa33c..15469f79b 100644 --- a/compiler/res/prog8lib/math.p8 +++ b/compiler/res/prog8lib/math.p8 @@ -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 + } } diff --git a/compiler/res/prog8lib/virtual/math.p8 b/compiler/res/prog8lib/virtual/math.p8 index a9d0aacc9..194c30187 100644 --- a/compiler/res/prog8lib/virtual/math.p8 +++ b/compiler/res/prog8lib/virtual/math.p8 @@ -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 + } } diff --git a/docs/source/libraries.rst b/docs/source/libraries.rst index ff439e2cc..cb9a03227 100644 --- a/docs/source/libraries.rst +++ b/docs/source/libraries.rst @@ -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 -------- diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 44332bfdc..b03a69203 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -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 diff --git a/examples/bench8/crc16.p8 b/examples/bench8/crc16.p8 deleted file mode 100644 index ab741e818..000000000 --- a/examples/bench8/crc16.p8 +++ /dev/null @@ -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) - } -} diff --git a/examples/bench8/crc32.p8 b/examples/bench8/crc32.p8 deleted file mode 100644 index 22ec8b854..000000000 --- a/examples/bench8/crc32.p8 +++ /dev/null @@ -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) - } -} diff --git a/examples/bench8/crc8.p8 b/examples/bench8/crc8.p8 deleted file mode 100644 index 73613d461..000000000 --- a/examples/bench8/crc8.p8 +++ /dev/null @@ -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) - } -} diff --git a/examples/bench8/pow.p8 b/examples/bench8/pow.p8 deleted file mode 100644 index a992ce866..000000000 --- a/examples/bench8/pow.p8 +++ /dev/null @@ -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) - } -} diff --git a/examples/bench8/readme.txt b/examples/bench8/readme.txt deleted file mode 100644 index a0d5f746f..000000000 --- a/examples/bench8/readme.txt +++ /dev/null @@ -1 +0,0 @@ -Contains several benchmarks from https://gglabs.us/node/2293 ported to prog8. diff --git a/examples/bench8/sieve-bit.p8 b/examples/bench8/sieve-bit.p8 deleted file mode 100644 index e45f32a87..000000000 --- a/examples/bench8/sieve-bit.p8 +++ /dev/null @@ -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 - } -} diff --git a/examples/bench8/sieve.p8 b/examples/bench8/sieve.p8 deleted file mode 100644 index 0a5ba03e1..000000000 --- a/examples/bench8/sieve.p8 +++ /dev/null @@ -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) - } -} diff --git a/examples/test.p8 b/examples/test.p8 index 3be700990..72259fc75 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -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() } }