;;******************************************************************************** ;; @file ;; @brief Ringbuffer ;; @details ;; Size of the ringbuffer is RBUF_MEM_END - RBUF_MEM_START - 2, since two bytes ;; are used by the read and write pointer ;; The `RBUF_NAME` variable must be defined, the functions will then be exported ;; as `rb__` where `` = `init`, `read` or `write` ;; ;; @note ;; Doxygen can not generate proper documentation for this module, because ;; all names are defined using macros ;; @requires ;; RBUF_MEM_START: First address of ringbuffer memory space ;; RBUF_MEM_END: Last address of ringbuffer memory space ;; RBUF_NAME: Name of the ringbuffer ;; @ingroup libs ;;******************************************************************************** .code .ifndef RBUF_MEM_START .fatal "RBUF_MEM_START not defined" .endif .ifndef RBUF_MEM_END .fatal "RBUF_MEM_END not defined" .endif ; can not detect if RBUF_NAME is defined, if it is not you will get ; "String constant expected" Error on the line below .define _RBUF_NAME .concat("rb_", RBUF_NAME) RB_WRITE = RBUF_MEM_START ; write pointer, relative to RB_WRITE RB_READ = RBUF_MEM_START + 1 ; read ponter, relative to RB_START RB_START = RBUF_MEM_START + 2 RB_LENGTH = RBUF_MEM_END - RBUF_MEM_START - 2 .if RB_LENGTH < 1 .fatal "buffer size too small, must be at least 1" .endif .if RB_LENGTH > $ff .fatal "buffer size too large, must be <= $ff" .endif ;;******************************************************************************** ;; @function Initialize the buffer ;;******************************************************************************** .ident(.concat(_RBUF_NAME, "_init")): .scope stz RB_WRITE stz RB_READ rts .endscope ;;******************************************************************************** ;; @function Read a value from the buffer ;; @details ;; If there is no value to be read, the Pz will be set ;; @returns A: value ;; @modifies A, X ;;******************************************************************************** .ident(.concat(_RBUF_NAME, "_read")): .scope ldx RB_READ cpx RB_WRITE beq @rb_read_rts ; if buffer empty lda RB_START,x inx ; increment RB_READ pointer, not using macro bec. of unknown Pz cpx #RB_LENGTH beq @read_wrap stx RB_READ @rb_read_rts: rts @read_wrap: ; ptr == RB_LENGTH -> ptr = 0 stz RB_READ ; make sure Pz is not set ldx #$01 rts .endscope ;;******************************************************************************** ;; @function Write a value to the buffer ;; @param A: value to store ;; @modifies X ;;******************************************************************************** .ident(.concat(_RBUF_NAME, "_write")): .scope ; lda kp_VALUES, x ; load the char in a ldx RB_WRITE sta RB_START,x inx ; increment write pointer cpx #RB_LENGTH beq @write_wrap stx RB_WRITE @check_buf_full: ; increment read if buffer is full cpx RB_READ beq @read_inc rts @write_wrap: ; ptr == RB_LENGTH -> ptr = 0 stz RB_WRITE ldx #0 bra @check_buf_full @read_inc: ldx RB_READ inx cpx #RB_LENGTH beq @read_wrap stx RB_READ rts @read_wrap: ; ptr == RB_LENGTH -> ptr = 0 stz RB_READ rts .endscope .undefine _RBUF_NAME .undefine RBUF_NAME