; **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 = 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
    }
}


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 = 0
    uword head = 0
    uword tail = 8191
    uword buffer_ptr = memory("buffers_ringbuffer", 8192, 0)

    sub init() {
        head = fill = 0
        tail = 8191
    }

    sub size() -> uword {
        return fill
    }

    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
        inc_head()
        fill++
    }

    sub putw(uword value) {
        ; -- store a word in the buffer
        fill += 2
        buffer_ptr[head] = lsb(value)
        inc_head()
        buffer_ptr[head] = msb(value)
        inc_head()
    }

    sub get() -> ubyte {
        ; -- retrieves a byte from the buffer
        fill--
        inc_tail()
        return buffer_ptr[tail]
    }

    sub getw() -> uword {
        ; -- retrieves a word from the buffer
        fill -= 2
        inc_tail()
        cx16.r0L = buffer_ptr[tail]
        inc_tail()
        cx16.r0H = buffer_ptr[tail]
        return cx16.r0
    }

    sub inc_head() {
        head++
        if msb(head)==$20
            head=0
    }

    sub inc_tail() {
        tail++
        if msb(tail)==$20
            tail=0
    }
}

