This protects against race conditions. We can now preset the first two bytes which are used for size and flags by the COM module (currently the only user of the ringbuffer module).
244 lines
5.7 KiB
NASM
244 lines
5.7 KiB
NASM
|
|
|
|
.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_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 yl
|
|
push yh
|
|
clr r17
|
|
add yl, r16
|
|
adc yh, r17
|
|
std y+RINGBUFFER_OFFS_DATA, r17 ; (length byte in COM module)
|
|
std y+RINGBUFFER_OFFS_DATA+1, r17 ; (flags byte in COM module)
|
|
pop yh
|
|
pop yl
|
|
|
|
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?
|
|
brcc 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
|
|
brcc 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
|
|
brcc RingBuffer_Read_end
|
|
sub r18, r19
|
|
|
|
RingBuffer_Read_end:
|
|
ret
|
|
|
|
|
|
|
|
|
|
|
|
|