mirror of
https://github.com/irmen/prog8.git
synced 2024-12-23 09:32:43 +00:00
improved buffers library, added to docs
This commit is contained in:
parent
bc9683cc54
commit
5406a992f5
@ -1,69 +1,130 @@
|
|||||||
; **experimental** buffer data structures, API subject to change!!
|
; **experimental** buffer data structures, API subject to change!!
|
||||||
|
|
||||||
|
|
||||||
%option no_symbol_prefixing, ignore_unused
|
%option no_symbol_prefixing, ignore_unused
|
||||||
|
|
||||||
smallringbuffer {
|
|
||||||
; -- A ringbuffer (FIFO queue) that occupies a single page in memory, containing 255 bytes maximum.
|
|
||||||
; You can store and retrieve bytes and words too.
|
|
||||||
; It's optimized for speed and depends on the byte-wrap-around feature when doing incs and decs.
|
|
||||||
|
|
||||||
ubyte fill
|
smallringbuffer {
|
||||||
ubyte head
|
; -- A ringbuffer (FIFO queue) that occupies 256 bytes in memory.
|
||||||
ubyte tail
|
; You can store and retrieve bytes and words. No guards against over/underflow.
|
||||||
|
; It's optimized for speed and depends on the byte-wrap-around when doing incs and decs.
|
||||||
|
|
||||||
|
ubyte fill = 0
|
||||||
|
ubyte head = 0
|
||||||
|
ubyte tail = 255
|
||||||
ubyte[256] buffer
|
ubyte[256] buffer
|
||||||
|
|
||||||
sub init() {
|
sub init() {
|
||||||
; -- (re)initialize the ringbuffer, you must call this before using the other routines
|
; -- (re)initialize the ringbuffer
|
||||||
head = fill = 0
|
head = fill = 0
|
||||||
tail = 255
|
tail = 255
|
||||||
}
|
}
|
||||||
|
|
||||||
sub put(ubyte value) -> bool {
|
sub size() -> ubyte {
|
||||||
; -- store a byte in the buffer, returns success
|
return fill
|
||||||
if fill==255
|
}
|
||||||
return false
|
|
||||||
|
sub free() -> ubyte {
|
||||||
|
return 255-fill
|
||||||
|
}
|
||||||
|
|
||||||
|
sub isfull() -> bool {
|
||||||
|
return fill>=254
|
||||||
|
}
|
||||||
|
|
||||||
|
sub isempty() -> bool {
|
||||||
|
return fill<=1
|
||||||
|
}
|
||||||
|
|
||||||
|
sub put(ubyte value) {
|
||||||
|
; -- store a byte in the buffer
|
||||||
buffer[head] = value
|
buffer[head] = value
|
||||||
head++
|
head++
|
||||||
fill++
|
fill++
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub putw(uword value) -> bool {
|
sub putw(uword value) {
|
||||||
; -- store a word in the buffer, returns success
|
; -- store a word in the buffer
|
||||||
if fill>=254
|
|
||||||
return false
|
|
||||||
fill += 2
|
fill += 2
|
||||||
buffer[head] = lsb(value)
|
buffer[head] = lsb(value)
|
||||||
head++
|
head++
|
||||||
buffer[head] = msb(value)
|
buffer[head] = msb(value)
|
||||||
head++
|
head++
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub get() -> ubyte {
|
sub get() -> ubyte {
|
||||||
; -- retrieves a byte from the buffer. Also sets Carry flag: set=success, clear=buffer was empty
|
; -- retrieves a byte from the buffer
|
||||||
if fill==0 {
|
|
||||||
sys.clear_carry()
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
fill--
|
fill--
|
||||||
tail++
|
tail++
|
||||||
sys.set_carry()
|
|
||||||
return buffer[tail]
|
return buffer[tail]
|
||||||
}
|
}
|
||||||
|
|
||||||
sub getw() -> uword {
|
sub getw() -> uword {
|
||||||
; -- retrieves a word from the buffer. Also sets Carry flag: set=success, clear=buffer was empty
|
; -- retrieves a word from the buffer
|
||||||
if fill<2 {
|
|
||||||
sys.clear_carry()
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
fill -= 2
|
fill -= 2
|
||||||
tail++
|
tail++
|
||||||
cx16.r0L = buffer[tail]
|
cx16.r0L = buffer[tail]
|
||||||
tail++
|
tail++
|
||||||
cx16.r0H = buffer[tail]
|
cx16.r0H = buffer[tail]
|
||||||
sys.set_carry()
|
return cx16.r0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
; note: for a "small stack" (256 bytes size) just use the CPU stack via sys.push[w] / sys.pop[w].
|
||||||
|
|
||||||
|
stack {
|
||||||
|
; -- A stack (LIFO) that uses a block of 8 KB of memory. Growing downward from the top of the buffer.
|
||||||
|
; You can store and retrieve bytes and words. There are no guards against stack over/underflow.
|
||||||
|
|
||||||
|
uword sp = 8191
|
||||||
|
uword buffer_ptr = memory("buffers_stack", 8192, 0)
|
||||||
|
|
||||||
|
sub init() {
|
||||||
|
sp = 8191
|
||||||
|
}
|
||||||
|
|
||||||
|
sub size() -> uword {
|
||||||
|
return 8191-sp
|
||||||
|
}
|
||||||
|
|
||||||
|
sub free() -> uword {
|
||||||
|
return sp
|
||||||
|
}
|
||||||
|
|
||||||
|
sub isfull() -> bool {
|
||||||
|
return sp==0
|
||||||
|
}
|
||||||
|
|
||||||
|
sub isempty() -> bool {
|
||||||
|
return sp==8191
|
||||||
|
}
|
||||||
|
|
||||||
|
sub push(ubyte value) {
|
||||||
|
; -- put a byte on the stack
|
||||||
|
buffer_ptr[sp] = value
|
||||||
|
sp--
|
||||||
|
}
|
||||||
|
|
||||||
|
sub pushw(uword value) {
|
||||||
|
; -- put a word on the stack (lsb first then msb)
|
||||||
|
buffer_ptr[sp] = lsb(value)
|
||||||
|
sp--
|
||||||
|
buffer_ptr[sp] = msb(value)
|
||||||
|
sp--
|
||||||
|
}
|
||||||
|
|
||||||
|
sub pop() -> ubyte {
|
||||||
|
; -- pops a byte off the stack
|
||||||
|
sp++
|
||||||
|
return buffer_ptr[sp]
|
||||||
|
}
|
||||||
|
|
||||||
|
sub popw() -> uword {
|
||||||
|
; -- pops a word off the stack.
|
||||||
|
sp++
|
||||||
|
cx16.r0H = buffer_ptr[sp]
|
||||||
|
sp++
|
||||||
|
cx16.r0L = buffer_ptr[sp]
|
||||||
return cx16.r0
|
return cx16.r0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,66 +132,64 @@ smallringbuffer {
|
|||||||
|
|
||||||
ringbuffer {
|
ringbuffer {
|
||||||
; -- A ringbuffer (FIFO queue) that uses a block of 8 KB of memory.
|
; -- A ringbuffer (FIFO queue) that uses a block of 8 KB of memory.
|
||||||
; You can store and retrieve bytes and words too.
|
; You can store and retrieve bytes and words too. No guards against buffer under/overflow.
|
||||||
|
|
||||||
uword fill
|
uword fill = 0
|
||||||
uword head
|
uword head = 0
|
||||||
uword tail
|
uword tail = 8191
|
||||||
uword buffer_ptr = memory("ringbuffer", 8192, 0)
|
uword buffer_ptr = memory("buffers_ringbuffer", 8192, 0)
|
||||||
|
|
||||||
sub init() {
|
sub init() {
|
||||||
; -- (re)initialize the ringbuffer, you must call this before using the other routines
|
|
||||||
head = fill = 0
|
head = fill = 0
|
||||||
tail = 8191
|
tail = 8191
|
||||||
}
|
}
|
||||||
|
|
||||||
sub put(ubyte value) -> bool {
|
sub size() -> uword {
|
||||||
; -- store a byte in the buffer, returns success
|
return fill
|
||||||
if fill==8192
|
}
|
||||||
return false
|
|
||||||
|
sub free() -> uword {
|
||||||
|
return 8191-fill
|
||||||
|
}
|
||||||
|
|
||||||
|
sub isempty() -> bool {
|
||||||
|
return fill==0
|
||||||
|
}
|
||||||
|
|
||||||
|
sub isfull() -> bool {
|
||||||
|
return fill>=8191
|
||||||
|
}
|
||||||
|
|
||||||
|
sub put(ubyte value) {
|
||||||
|
; -- store a byte in the buffer
|
||||||
buffer_ptr[head] = value
|
buffer_ptr[head] = value
|
||||||
inc_head()
|
inc_head()
|
||||||
fill++
|
fill++
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub putw(uword value) -> bool {
|
sub putw(uword value) {
|
||||||
; -- store a word in the buffer, returns success
|
; -- store a word in the buffer
|
||||||
if fill>=8191
|
|
||||||
return false
|
|
||||||
fill += 2
|
fill += 2
|
||||||
buffer_ptr[head] = lsb(value)
|
buffer_ptr[head] = lsb(value)
|
||||||
inc_head()
|
inc_head()
|
||||||
buffer_ptr[head] = msb(value)
|
buffer_ptr[head] = msb(value)
|
||||||
inc_head()
|
inc_head()
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub get() -> ubyte {
|
sub get() -> ubyte {
|
||||||
; -- retrieves a byte from the buffer. Also sets Carry flag: set=success, clear=buffer was empty
|
; -- retrieves a byte from the buffer
|
||||||
if fill==0 {
|
|
||||||
sys.clear_carry()
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
fill--
|
fill--
|
||||||
inc_tail()
|
inc_tail()
|
||||||
cx16.r0L = buffer_ptr[tail]
|
return buffer_ptr[tail]
|
||||||
sys.set_carry()
|
|
||||||
return cx16.r0L
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub getw() -> uword {
|
sub getw() -> uword {
|
||||||
; -- retrieves a word from the buffer. Also sets Carry flag: set=success, clear=buffer was empty
|
; -- retrieves a word from the buffer
|
||||||
if fill<2 {
|
|
||||||
sys.clear_carry()
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
fill -= 2
|
fill -= 2
|
||||||
inc_tail()
|
inc_tail()
|
||||||
cx16.r0L = buffer_ptr[tail]
|
cx16.r0L = buffer_ptr[tail]
|
||||||
inc_tail()
|
inc_tail()
|
||||||
cx16.r0H = buffer_ptr[tail]
|
cx16.r0H = buffer_ptr[tail]
|
||||||
sys.set_carry()
|
|
||||||
return cx16.r0
|
return cx16.r0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,6 +206,3 @@ ringbuffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
; TODO ringbuffer (FIFO queue) should use banked ram on the X16, but still work on virtual target
|
|
||||||
; TODO stack (LIFO queue) using more than 1 page of ram (maybe even banked ram on the x16)
|
|
||||||
|
244
compiler/res/prog8lib/cx16/buffers.p8
Normal file
244
compiler/res/prog8lib/cx16/buffers.p8
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
; **experimental** buffer data structures, API subject to change!!
|
||||||
|
|
||||||
|
%option no_symbol_prefixing, ignore_unused
|
||||||
|
|
||||||
|
smallringbuffer {
|
||||||
|
; -- A ringbuffer (FIFO queue) that occupies 256 bytes in memory.
|
||||||
|
; You can store and retrieve bytes and words. No guards against over/underflow.
|
||||||
|
; It's optimized for speed and depends on the byte-wrap-around when doing incs and decs.
|
||||||
|
|
||||||
|
ubyte fill = 0
|
||||||
|
ubyte head = 0
|
||||||
|
ubyte tail = 255
|
||||||
|
ubyte[256] buffer
|
||||||
|
|
||||||
|
sub init() {
|
||||||
|
; -- (re)initialize the ringbuffer
|
||||||
|
head = fill = 0
|
||||||
|
tail = 255
|
||||||
|
}
|
||||||
|
|
||||||
|
sub size() -> ubyte {
|
||||||
|
return fill
|
||||||
|
}
|
||||||
|
|
||||||
|
sub free() -> ubyte {
|
||||||
|
return 255-fill
|
||||||
|
}
|
||||||
|
|
||||||
|
sub isfull() -> bool {
|
||||||
|
return fill>=254
|
||||||
|
}
|
||||||
|
|
||||||
|
sub isempty() -> bool {
|
||||||
|
return fill<=1
|
||||||
|
}
|
||||||
|
|
||||||
|
sub put(ubyte value) {
|
||||||
|
; -- store a byte in the buffer
|
||||||
|
buffer[head] = value
|
||||||
|
head++
|
||||||
|
fill++
|
||||||
|
}
|
||||||
|
|
||||||
|
sub putw(uword value) {
|
||||||
|
; -- store a word in the buffer
|
||||||
|
fill += 2
|
||||||
|
buffer[head] = lsb(value)
|
||||||
|
head++
|
||||||
|
buffer[head] = msb(value)
|
||||||
|
head++
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get() -> ubyte {
|
||||||
|
; -- retrieves a byte from the buffer
|
||||||
|
fill--
|
||||||
|
tail++
|
||||||
|
return buffer[tail]
|
||||||
|
}
|
||||||
|
|
||||||
|
sub getw() -> uword {
|
||||||
|
; -- retrieves a word from the buffer
|
||||||
|
fill -= 2
|
||||||
|
tail++
|
||||||
|
cx16.r0L = buffer[tail]
|
||||||
|
tail++
|
||||||
|
cx16.r0H = buffer[tail]
|
||||||
|
return cx16.r0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
; note: for a "small stack" (256 bytes size) just use the CPU stack via sys.push[w] / sys.pop[w].
|
||||||
|
|
||||||
|
stack {
|
||||||
|
; -- A stack (LIFO) that uses a block of 8 KB of memory. Growing downward from the top of the buffer.
|
||||||
|
; You can store and retrieve bytes and words. There are no guards against stack over/underflow.
|
||||||
|
|
||||||
|
uword sp
|
||||||
|
ubyte bank
|
||||||
|
|
||||||
|
sub init(ubyte rambank) {
|
||||||
|
; -- initialize the stack, must be called before use. Supply the HiRAM bank to use as buffer space.
|
||||||
|
sp = $bfff
|
||||||
|
bank = rambank
|
||||||
|
}
|
||||||
|
|
||||||
|
sub size() -> uword {
|
||||||
|
return $bfff-sp
|
||||||
|
}
|
||||||
|
|
||||||
|
sub free() -> uword {
|
||||||
|
return sp-$a000
|
||||||
|
}
|
||||||
|
|
||||||
|
sub isfull() -> bool {
|
||||||
|
return sp<=$a001
|
||||||
|
}
|
||||||
|
|
||||||
|
sub isempty() -> bool {
|
||||||
|
return sp==$bfff
|
||||||
|
}
|
||||||
|
|
||||||
|
sub push(ubyte value) {
|
||||||
|
; -- put a byte on the stack
|
||||||
|
sys.push(cx16.getrambank())
|
||||||
|
cx16.rambank(bank)
|
||||||
|
|
||||||
|
@(sp) = value
|
||||||
|
sp--
|
||||||
|
|
||||||
|
cx16.rambank(sys.pop())
|
||||||
|
}
|
||||||
|
|
||||||
|
sub pushw(uword value) {
|
||||||
|
; -- put a word on the stack (lsb first then msb)
|
||||||
|
sys.push(cx16.getrambank())
|
||||||
|
cx16.rambank(bank)
|
||||||
|
|
||||||
|
@(sp) = lsb(value)
|
||||||
|
sp--
|
||||||
|
@(sp) = msb(value)
|
||||||
|
sp--
|
||||||
|
|
||||||
|
cx16.rambank(sys.pop())
|
||||||
|
}
|
||||||
|
|
||||||
|
sub pop() -> ubyte {
|
||||||
|
; -- pops a byte off the stack
|
||||||
|
sys.push(cx16.getrambank())
|
||||||
|
cx16.rambank(bank)
|
||||||
|
|
||||||
|
sp++
|
||||||
|
cx16.r0L = @(sp)
|
||||||
|
cx16.rambank(sys.pop())
|
||||||
|
return cx16.r0L
|
||||||
|
}
|
||||||
|
|
||||||
|
sub popw() -> uword {
|
||||||
|
; -- pops a word off the stack.
|
||||||
|
sys.push(cx16.getrambank())
|
||||||
|
cx16.rambank(bank)
|
||||||
|
|
||||||
|
sp++
|
||||||
|
cx16.r0H = @(sp)
|
||||||
|
sp++
|
||||||
|
cx16.r0L = @(sp)
|
||||||
|
cx16.rambank(sys.pop())
|
||||||
|
return cx16.r0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ringbuffer {
|
||||||
|
; -- A ringbuffer (FIFO queue) that uses a block of 8 KB of memory.
|
||||||
|
; You can store and retrieve bytes and words too. No guards against buffer under/overflow.
|
||||||
|
|
||||||
|
uword fill, head, tail
|
||||||
|
ubyte bank = 255 ; set via init()
|
||||||
|
|
||||||
|
sub init(ubyte rambank) {
|
||||||
|
; -- initialize the ringbuffer, must be called before use. Supply the HiRAM bank to use as buffer space.
|
||||||
|
head = $a000
|
||||||
|
tail = $bfff
|
||||||
|
fill = 0
|
||||||
|
bank = rambank
|
||||||
|
}
|
||||||
|
|
||||||
|
sub size() -> uword {
|
||||||
|
return fill
|
||||||
|
}
|
||||||
|
|
||||||
|
sub free() -> uword {
|
||||||
|
return $1fff-fill
|
||||||
|
}
|
||||||
|
|
||||||
|
sub isempty() -> bool {
|
||||||
|
return fill<=1
|
||||||
|
}
|
||||||
|
|
||||||
|
sub isfull() -> bool {
|
||||||
|
return fill>=8191
|
||||||
|
}
|
||||||
|
|
||||||
|
sub put(ubyte value) {
|
||||||
|
; -- store a byte in the buffer
|
||||||
|
sys.push(cx16.getrambank())
|
||||||
|
cx16.rambank(bank)
|
||||||
|
|
||||||
|
@(head) = value
|
||||||
|
fill++
|
||||||
|
inc_head()
|
||||||
|
cx16.rambank(sys.pop())
|
||||||
|
}
|
||||||
|
|
||||||
|
sub putw(uword value) {
|
||||||
|
; -- store a word in the buffer
|
||||||
|
sys.push(cx16.getrambank())
|
||||||
|
cx16.rambank(bank)
|
||||||
|
|
||||||
|
pokew(head, value)
|
||||||
|
fill += 2
|
||||||
|
inc_head()
|
||||||
|
inc_head()
|
||||||
|
cx16.rambank(sys.pop())
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get() -> ubyte {
|
||||||
|
; -- retrieves a byte from the buffer
|
||||||
|
sys.push(cx16.getrambank())
|
||||||
|
cx16.rambank(bank)
|
||||||
|
|
||||||
|
fill--
|
||||||
|
inc_tail()
|
||||||
|
cx16.r0L= @(tail)
|
||||||
|
cx16.rambank(sys.pop())
|
||||||
|
return cx16.r0L
|
||||||
|
}
|
||||||
|
|
||||||
|
sub getw() -> uword {
|
||||||
|
; -- retrieves a word from the buffer
|
||||||
|
sys.push(cx16.getrambank())
|
||||||
|
cx16.rambank(bank)
|
||||||
|
|
||||||
|
fill -= 2
|
||||||
|
inc_tail()
|
||||||
|
cx16.r0L = @(tail)
|
||||||
|
inc_tail()
|
||||||
|
cx16.r0H = @(tail)
|
||||||
|
cx16.rambank(sys.pop())
|
||||||
|
return cx16.r0
|
||||||
|
}
|
||||||
|
|
||||||
|
sub inc_head() {
|
||||||
|
head++
|
||||||
|
if msb(head)==$c0
|
||||||
|
head=$a000
|
||||||
|
}
|
||||||
|
|
||||||
|
sub inc_tail() {
|
||||||
|
tail++
|
||||||
|
if msb(tail)==$c0
|
||||||
|
tail=$a000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -410,6 +410,51 @@ Routines to check if any or all values in an array or memory buffer are not zero
|
|||||||
Doesn't work on split arrays.
|
Doesn't work on split arrays.
|
||||||
|
|
||||||
|
|
||||||
|
buffers (experimental)
|
||||||
|
----------------------
|
||||||
|
A small library providing a 8 KB stack, an 8 KB ringbuffer, and a fast 256 bytes ringbuffer.
|
||||||
|
Stack is a LIFO container, ringbuffers are FIFO containers.
|
||||||
|
On the Commander X16 the stack and ringbuffer will use a HiRAM bank instead of system ram,
|
||||||
|
you have to initialize that via the init(bank) routine.
|
||||||
|
|
||||||
|
Read the `buffers source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/diskio.p8>`_
|
||||||
|
to see what's in there. Note that the init() routines have that extra bank parameter on the cx16.
|
||||||
|
|
||||||
|
|
||||||
|
compression
|
||||||
|
-----------
|
||||||
|
Routines for data compression and decompression. Currently only the 'ByteRun1' aka 'PackBits' RLE encoding
|
||||||
|
is available. This is the compression that was also used in Amiga IFF images and in old MacPaint images.
|
||||||
|
|
||||||
|
``encode_rle (uword data, uword size, uword target, bool is_last_block) -> uword``
|
||||||
|
Compress the given data block using ByteRun1 aka PackBits RLE encoding.
|
||||||
|
Returns the size of the compressed RLE data. Worst case result storage size needed = (size + (size+126) / 127) + 1.
|
||||||
|
'is_last_block' = usually true, but you can set it to false if you want to concatenate multiple
|
||||||
|
compressed blocks (for instance if the source data is >64Kb)
|
||||||
|
|
||||||
|
``encode_rle_outfunc (uword data, uword size, uword output_function, bool is_last_block)``
|
||||||
|
Like ``encode_rle`` but not with an output buffer, but with an 'output_function' argument.
|
||||||
|
This is the address of a routine that gets a byte arg in A,
|
||||||
|
which is the next RLE byte to write to the compressed output buffer or file.
|
||||||
|
|
||||||
|
``decode_rle (uword compressed, uword target, uword maxsize) -> uword``
|
||||||
|
Decodes "ByteRun1" (aka PackBits) RLE compressed data. Control byte value 128 ends the decoding.
|
||||||
|
Also stops decompressing if the maxsize has been reached. Returns the size of the decompressed data.
|
||||||
|
|
||||||
|
``decode_rle_srcfunc (uword source_function, uword target, uword maxsize) -> uword``
|
||||||
|
Decodes "ByteRun1" (aka PackBits) RLE compressed data. Control byte value 128 ends the decoding.
|
||||||
|
Also stops decompressing when the maxsize has been reached. Returns the size of the decompressed data.
|
||||||
|
Instead of a source buffer, you provide a callback function that must return the next byte to compress in A.
|
||||||
|
|
||||||
|
``decode_rle_vram (uword compressed, ubyte vbank, uword vaddr)`` (cx16 only)
|
||||||
|
Decodes "ByteRun1" (aka PackBits) RLE compressed data directly into Vera VRAM.
|
||||||
|
Control byte value 128 ends the decoding.
|
||||||
|
While the X16 has pretty fast lzsa decompression in the kernal, RLE is still a lot faster to decode.
|
||||||
|
However it also doesn't compress data nearly as well, but that's the usual tradeoff.
|
||||||
|
There is a *compression* routine as well for RLE that you can run on the X16 itself,
|
||||||
|
something that the lzsa compression lacks.
|
||||||
|
|
||||||
|
|
||||||
conv
|
conv
|
||||||
----
|
----
|
||||||
Routines to convert strings to numbers or vice versa.
|
Routines to convert strings to numbers or vice versa.
|
||||||
@ -928,37 +973,6 @@ the `bmx source code <https://github.com/irmen/prog8/tree/master/compiler/res/pr
|
|||||||
There's also the "showbmx" example to look at.
|
There's also the "showbmx" example to look at.
|
||||||
|
|
||||||
|
|
||||||
compression
|
|
||||||
-----------
|
|
||||||
Routines for data compression and decompression. Currently only the 'ByteRun1' aka 'PackBits' RLE encoding
|
|
||||||
is available. This is the compression that was also used in Amiga IFF images and in old MacPaint images.
|
|
||||||
|
|
||||||
``encode_rle (uword data, uword size, uword target, bool is_last_block) -> uword``
|
|
||||||
Compress the given data block using ByteRun1 aka PackBits RLE encoding.
|
|
||||||
Returns the size of the compressed RLE data. Worst case result storage size needed = (size + (size+126) / 127) + 1.
|
|
||||||
'is_last_block' = usually true, but you can set it to false if you want to concatenate multiple
|
|
||||||
compressed blocks (for instance if the source data is >64Kb)
|
|
||||||
|
|
||||||
``encode_rle_outfunc (uword data, uword size, uword output_function, bool is_last_block)``
|
|
||||||
Like ``encode_rle`` but not with an output buffer, but with an 'output_function' argument.
|
|
||||||
This is the address of a routine that gets a byte arg in A,
|
|
||||||
which is the next RLE byte to write to the compressed output buffer or file.
|
|
||||||
|
|
||||||
``decode_rle (uword compressed, uword target, uword maxsize) -> uword``
|
|
||||||
Decodes "ByteRun1" (aka PackBits) RLE compressed data. Control byte value 128 ends the decoding.
|
|
||||||
Also stops decompressing if the maxsize has been reached. Returns the size of the decompressed data.
|
|
||||||
|
|
||||||
``decode_rle_srcfunc (uword source_function, uword target, uword maxsize) -> uword``
|
|
||||||
Decodes "ByteRun1" (aka PackBits) RLE compressed data. Control byte value 128 ends the decoding.
|
|
||||||
Also stops decompressing when the maxsize has been reached. Returns the size of the decompressed data.
|
|
||||||
Instead of a source buffer, you provide a callback function that must return the next byte to compress in A.
|
|
||||||
|
|
||||||
``decode_rle_vram (uword compressed, ubyte vbank, uword vaddr)`` (cx16 only)
|
|
||||||
Decodes "ByteRun1" (aka PackBits) RLE compressed data directly into Vera VRAM.
|
|
||||||
Control byte value 128 ends the decoding.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
emudbg (cx16 only)
|
emudbg (cx16 only)
|
||||||
-------------------
|
-------------------
|
||||||
X16Emu Emulator debug routines, for Cx16 only.
|
X16Emu Emulator debug routines, for Cx16 only.
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
TODO
|
TODO
|
||||||
====
|
====
|
||||||
|
|
||||||
work a bit more on the buffers library
|
|
||||||
|
|
||||||
document the @R0 - @R15 register support for normal subroutine parameters (footgun!)
|
document the @R0 - @R15 register support for normal subroutine parameters (footgun!)
|
||||||
|
|
||||||
make a compiler switch to disable footgun warnings
|
make a compiler switch to disable footgun warnings
|
||||||
|
|
||||||
|
upgrade zmskit example to use zsmkit v2
|
||||||
|
|
||||||
what to do with bankof(): keep it? add another syntax like \`value or ^value to get the bank byte?
|
what to do with bankof(): keep it? add another syntax like \`value or ^value to get the bank byte?
|
||||||
add a function like addr() or lsw() to complement bnk() in getting easy access to the lower 16 bits of a long integer?
|
|
||||||
-> added unary ^ operator as alternative to bankof()
|
-> added unary ^ operator as alternative to bankof()
|
||||||
-> added unary << operator as alternative to addr() / lsb(x>>16) / lsw()
|
-> added unary << operator as alternative to addr() / lsb(x>>16) / lsw()
|
||||||
-> added msw() and lsw() . note: msw() on a 24 bits constant can ALSO be used to get the bank byte because the value, while a word type, will be <=255
|
-> added msw() and lsw() . note: msw() on a 24 bits constant can ALSO be used to get the bank byte because the value, while a word type, will be <=255
|
||||||
|
119
examples/test.p8
119
examples/test.p8
@ -1,43 +1,106 @@
|
|||||||
%import textio
|
%import textio
|
||||||
|
%import buffers
|
||||||
|
|
||||||
|
%option no_sysinit
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
foo(42)
|
txt.print("stack\n")
|
||||||
foo(42)
|
test_stack()
|
||||||
foo(42)
|
txt.print("\nringbuffer\n")
|
||||||
bar(9999)
|
test_ring()
|
||||||
bar(9999)
|
txt.print("\nsmallringbuffer\n")
|
||||||
bar(9999)
|
test_smallring()
|
||||||
baz(42, 123)
|
|
||||||
baz(42, 123)
|
|
||||||
baz(42, 123)
|
|
||||||
meh(42, 9999)
|
|
||||||
meh(42, 9999)
|
|
||||||
meh(42, 9999)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub foo(ubyte arg @R0) {
|
sub test_stack() {
|
||||||
txt.print_ub(arg)
|
stack.init(2)
|
||||||
txt.nl()
|
txt.print_uw(stack.size())
|
||||||
}
|
|
||||||
|
|
||||||
sub bar(uword arg @R0) {
|
|
||||||
txt.print_uw(arg)
|
|
||||||
txt.nl()
|
|
||||||
}
|
|
||||||
|
|
||||||
sub baz(ubyte arg1 @R0, ubyte arg2 @R1) {
|
|
||||||
txt.print_ub(arg1)
|
|
||||||
txt.spc()
|
txt.spc()
|
||||||
txt.print_ub(arg2)
|
txt.print_uw(stack.free())
|
||||||
|
txt.nl()
|
||||||
|
stack.push(1)
|
||||||
|
stack.push(2)
|
||||||
|
stack.push(3)
|
||||||
|
stack.pushw(12345)
|
||||||
|
txt.print_uw(stack.size())
|
||||||
|
txt.spc()
|
||||||
|
txt.print_uw(stack.free())
|
||||||
|
txt.nl()
|
||||||
|
txt.nl()
|
||||||
|
txt.print_uw(stack.popw())
|
||||||
|
txt.nl()
|
||||||
|
txt.print_uw(stack.pop())
|
||||||
|
txt.nl()
|
||||||
|
txt.print_uw(stack.pop())
|
||||||
|
txt.nl()
|
||||||
|
txt.print_uw(stack.pop())
|
||||||
|
txt.nl()
|
||||||
|
txt.nl()
|
||||||
|
txt.print_uw(stack.size())
|
||||||
|
txt.spc()
|
||||||
|
txt.print_uw(stack.free())
|
||||||
txt.nl()
|
txt.nl()
|
||||||
}
|
}
|
||||||
|
|
||||||
sub meh(ubyte arg1 @R0, uword arg2 @R1) {
|
sub test_ring() {
|
||||||
txt.print_ub(arg1)
|
ringbuffer.init(2)
|
||||||
|
txt.print_uw(ringbuffer.size())
|
||||||
txt.spc()
|
txt.spc()
|
||||||
txt.print_uw(arg2)
|
txt.print_uw(ringbuffer.free())
|
||||||
|
txt.nl()
|
||||||
|
ringbuffer.put(1)
|
||||||
|
ringbuffer.put(2)
|
||||||
|
ringbuffer.put(3)
|
||||||
|
ringbuffer.putw(12345)
|
||||||
|
txt.print_uw(ringbuffer.size())
|
||||||
|
txt.spc()
|
||||||
|
txt.print_uw(ringbuffer.free())
|
||||||
|
txt.nl()
|
||||||
|
txt.nl()
|
||||||
|
txt.print_uw(ringbuffer.get())
|
||||||
|
txt.nl()
|
||||||
|
txt.print_uw(ringbuffer.get())
|
||||||
|
txt.nl()
|
||||||
|
txt.print_uw(ringbuffer.get())
|
||||||
|
txt.nl()
|
||||||
|
txt.print_uw(ringbuffer.getw())
|
||||||
|
txt.nl()
|
||||||
|
txt.nl()
|
||||||
|
txt.print_uw(ringbuffer.size())
|
||||||
|
txt.spc()
|
||||||
|
txt.print_uw(ringbuffer.free())
|
||||||
|
txt.nl()
|
||||||
|
}
|
||||||
|
|
||||||
|
sub test_smallring() {
|
||||||
|
smallringbuffer.init()
|
||||||
|
txt.print_uw(smallringbuffer.size())
|
||||||
|
txt.spc()
|
||||||
|
txt.print_uw(smallringbuffer.free())
|
||||||
|
txt.nl()
|
||||||
|
smallringbuffer.put(1)
|
||||||
|
smallringbuffer.put(2)
|
||||||
|
smallringbuffer.put(3)
|
||||||
|
smallringbuffer.putw(12345)
|
||||||
|
txt.print_uw(smallringbuffer.size())
|
||||||
|
txt.spc()
|
||||||
|
txt.print_uw(smallringbuffer.free())
|
||||||
|
txt.nl()
|
||||||
|
txt.nl()
|
||||||
|
txt.print_uw(smallringbuffer.get())
|
||||||
|
txt.nl()
|
||||||
|
txt.print_uw(smallringbuffer.get())
|
||||||
|
txt.nl()
|
||||||
|
txt.print_uw(smallringbuffer.get())
|
||||||
|
txt.nl()
|
||||||
|
txt.print_uw(smallringbuffer.getw())
|
||||||
|
txt.nl()
|
||||||
|
txt.nl()
|
||||||
|
txt.print_uw(smallringbuffer.size())
|
||||||
|
txt.spc()
|
||||||
|
txt.print_uw(smallringbuffer.free())
|
||||||
txt.nl()
|
txt.nl()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user