Files
aqhomecontrol/avr/common/ringbuffer.asm
Martin Preuss f806cf30e5 Revert "added ifdefs guards for includes."
This reverts commit 15199a17a5.
2025-04-21 00:46:57 +02:00

256 lines
6.2 KiB
NASM

; ***************************************************************************
; copyright : (C) 2023 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
.equ RINGBUFFER_OFFS_MAXSIZE = 0
.equ RINGBUFFER_OFFS_USED = 1
.equ RINGBUFFER_OFFS_READPOS = 2
.equ RINGBUFFER_OFFS_WRITEPOS = 3
.equ RINGBUFFER_OFFS_DATA = 4
.cseg
RINGBUFFER_BEGIN:
; ***************************************************************************
; RingBuffer_Init
;
; IN:
; - Y: base address of the ringbuffer in SRAM
; - R16: maximum size in bytes (pure data excluding headers like pos pointers etc).
; OUT:
; - R16: pos of allocated buffer
; REGISTERS MODIFIED: r16, r17, r18, r19, r20, r21
RingBuffer_Init:
clr r17
std y+RINGBUFFER_OFFS_MAXSIZE, r16
std y+RINGBUFFER_OFFS_USED, r17
std y+RINGBUFFER_OFFS_READPOS, r17
std y+RINGBUFFER_OFFS_WRITEPOS, r17
ret
; ***************************************************************************
; RingBuffer_Alloc
;
; IN:
; - Y: base address of the ringbuffer in SRAM
; - R16: number of bytes to allocate
; OUT:
; - R16: pos of allocated buffer
; REGISTERS MODIFIED: r16, r17, r18, r19, r20, r21
RingBuffer_Alloc:
in r21, SREG ; save global interrupt enable bit from SREG
cli
ldd r17, y+RINGBUFFER_OFFS_MAXSIZE
ldd r18, y+RINGBUFFER_OFFS_USED
ldd r19, y+RINGBUFFER_OFFS_WRITEPOS
cpi r16, 2 ; alloc at least two bytes
brcs RingBuffer_Alloc_error ; too few bytes
mov r20, r16 ; to_alloc
add r20, r18 ; to_alloc + used
cp r20, r17 ; new_used < max?
brcc RingBuffer_Alloc_error
std y+RINGBUFFER_OFFS_USED, r20
mov r20, r19 ; current write pos (for later)
add r19, r16 ; current_writepos+to_alloc
cp r19, r17 ; new_writepos < max?
brcs RingBuffer_Alloc_l1
sub r19, r17
RingBuffer_Alloc_l1:
std y+RINGBUFFER_OFFS_WRITEPOS, r19
mov r16, r20
; preset first byte (this is the length byte in COM module) with 0
push r16
mov r18, r16
clr r16
rcall RingBuffer_Write
rcall RingBuffer_Write
pop r16
out SREG, r21 ; restore global interrupt enable bit in SREG
sec
ret
RingBuffer_Alloc_error:
out SREG, r21
clc
ret
; ***************************************************************************
; RingBuffer_DeallocRead
;
; IN:
; - Y: base address of the ringbuffer in SRAM
; - R16: number of bytes to deallocate (e.g. number of bytes to skip in read ptr)
; OUT:
; - nothing
; REGISTERS MODIFIED: r17, r18, r19, r20, r21
RingBuffer_DeallocRead:
in r21, SREG
cli
ldd r17, y+RINGBUFFER_OFFS_MAXSIZE
ldd r18, y+RINGBUFFER_OFFS_USED
ldd r19, y+RINGBUFFER_OFFS_READPOS
mov r20, r18
sub r20, r16 ; used - to_dealloc
brcs RingBuffer_DeallocRead_error ; overflow -> error
std y+RINGBUFFER_OFFS_USED, r20
mov r20, r19 ; readpos
add r20, r16 ; readpos + to_dealloc
cp r20, r17 ; new readpos > max?
brcs RingBuffer_DeallocRead_l1 ; no, rjmp
sub r20, r17 ; wrap around
RingBuffer_DeallocRead_l1:
std y+RINGBUFFER_OFFS_READPOS, r20
out SREG, r21
sec
ret
RingBuffer_DeallocRead_error:
out SREG, r21
clc
ret
; ***************************************************************************
; RingBuffer_DeallocWrite
;
; IN:
; - Y: base address of the ringbuffer in SRAM
; - R16: number of bytes to deallocate (e.g. number of bytes to move back write ptr)
; OUT:
; - nothing
; REGISTERS MODIFIED: r17, r18, r19, r20, r21
RingBuffer_DeallocWrite:
in r21, SREG
cli
ldd r17, y+RINGBUFFER_OFFS_MAXSIZE
ldd r18, y+RINGBUFFER_OFFS_USED
ldd r19, y+RINGBUFFER_OFFS_WRITEPOS
mov r20, r18 ; used
sub r20, r16 ; used - to_dealloc
brcs RingBuffer_DeallocWrite_error ; overflow -> error
std y+RINGBUFFER_OFFS_USED, r20
mov r20, r19 ; writepos
sub r20, r16 ; writepos - to_dealloc
brcc RingBuffer_DeallocWrite_l1 ; no, rjmp
add r20, r17 ; wrap around
RingBuffer_DeallocWrite_l1:
std y+RINGBUFFER_OFFS_WRITEPOS, r20
out SREG, r21
sec
ret
RingBuffer_DeallocWrite_error:
out SREG, r21
clc
ret
; ***************************************************************************
; RingBuffer_Write
;
; Write a byte into the ringbuffer.
;
; IN:
; - Y: pointer to buffer
; - R16: byte to write
; - R18: pos pointer inside ring buffer to write to next
; - R19: maximum size of the ringbuffer (for wrap-around)
; OUT:
; - R18: incremented pos pointer inside ringbuffer
; MODIFIED REGS: r3, r22
RingBuffer_Write:
push yh
push yl
clr r3
ldi r22, RINGBUFFER_OFFS_DATA
add yl, r22
adc yh, r3
add yl, r18
adc yh, r3
st y, r16
pop yl
pop yh
inc r18
cp r18, r19 ; r19 > r18; yes: CF set
brcs RingBuffer_Write_end
sub r18, r19
RingBuffer_Write_end:
ret
; ***************************************************************************
; RingBuffer_Read
;
; Read a byte from the ringbuffer.
;
; IN:
; - Y: pointer to buffer
; - R18: pos pointer inside ring buffer to read from next
; - R19: maximum size of the ringbuffer (for wrap-around)
; OUT:
; - R16: byte read
; - R18: incremented pos pointer inside ringbuffer
; MODIFIED REGS: r3, r22
RingBuffer_Read:
push yh
push yl
clr r3
ldi r22, RINGBUFFER_OFFS_DATA
add yl, r22
adc yh, r3
add yl, r18
adc yh, r3
ld r16, y
pop yl
pop yh
inc r18
cp r18, r19
brcs RingBuffer_Read_end
sub r18, r19
RingBuffer_Read_end:
ret
RINGBUFFER_END:
.equ MODULE_SIZE_RINGBUFFER = RINGBUFFER_END-RINGBUFFER_BEGIN