/* circularbytebuffer-asm.S */
/*
This file is part of the AVR-circularbytebuffer.
Copyright (C) 2009 Daniel Otte (daniel.otte@rub.de)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
/**
* \file circularbytebuffer-asm.S
* \email daniel.otte@rub.de
* \author Daniel Otte
* \date 2009-07-25
* \license GPLv3 or later
* \ingroup circularbytebuffer
* \brief declaration for circular byte buffer
*/
/*
typedef struct {
uint8_t buffer_size;
uint8_t fillcount;
uint8_t* buffer;
uint8_t* head;
uint8_t* tail;
uint8_t* top;
} circularbytebuffer_t;
*/
#include "config.h"
#define BUFFER_SIZE_OFFSET 0
#define FILLCOUNT_OFFSET 1
#define BUFFER_OFFSET 2
#define HEAD_OFFSET 4
#define TAIL_OFFSET 6
#define TOP_OFFSET 8
#ifndef CIRCULARBYTEBUFFER_NO_MALLOC
# define CIRCULARBYTEBUFFER_NO_MALLOC 0
#endif
#ifndef CIRCULARBYTEBUFFER_NO_INIT2
# define CIRCULARBYTEBUFFER_NO_INIT2 0
#endif
#if CIRCULARBYTEBUFFER_NO_MALLOC==0
/******************************************************************************/
/*
* uint8_t circularbytebuffer_init(uint8_t buffersize, circularbytebuffer_t* cb){
* cb->buffer_size = buffersize;
* cb->buffer = malloc(buffersize);
* cb->head = cb->tail = cb->buffer;
* cb->top = cb->buffer + cb->buffer_size;
* cb->fillcount = 0;
* if(cb->buffer)
* return 1; / * success * /
* return 0; / * malloc failed * /
* }
*
* param buffersize: r24
* param cb: r22:r23
*/
.global circularbytebuffer_init
circularbytebuffer_init:
push r28
push r29
movw r28, r22
std Y+0, r24 /* set buffer_size */
std Y+1, r1 /* set fillcount to 0 */
clr r25
call malloc
adiw r24, 0
brne 10f
clr r24
rjmp 99f
10:
std Y+2, r24
std Y+3, r25
std Y+4, r24
std Y+5, r25
std Y+6, r24
std Y+7, r25
ld r22, Y
add r24, r22
adc r25, r1
std Y+8, r24
std Y+9, r25
ldi r24, 1
99:
clr r25
pop r29
pop r28
ret
/******************************************************************************/
/*
* void circularbytebuffer_free(circularbytebuffer_t* cb){
* free(cb->buffer);
* }
*
* param cb: r24:r25
*/
.global circularbytebuffer_free
circularbytebuffer_free:
movw r30, r24
ldd r24, Z+BUFFER_OFFSET
ldd r25, Z+BUFFER_OFFSET+1
jmp free
#endif /* CIRCULARBYTEBUFFER_NO_MALLOC==0 */
#if CIRCULARBYTEBUFFER_NO_INIT2==0
/******************************************************************************/
/*
* void circularbytebuffer_init2(uint8_t buffersize, circularbytebuffer_t* cb, void* buffer){
* cb->buffer_size = buffersize;
* cb->buffer = buffer
* cb->head = cb->tail = cb->buffer;
* cb->top = cb->buffer + cb->buffer_size;
* cb->fillcount = 0;
* }
*
* param buffersize: r24
* param cb: r22:r23
* param buffer: r20:r21
*/
.global circularbytebuffer_init2
circularbytebuffer_init2:
movw r30, r22
std Z+0, r24 /* set buffer_size */
std Z+1, r1 /* set fillcount to 0 */
std Z+2, r20
std Z+3, r21
std Z+4, r20
std Z+5, r21
std Z+6, r20
std Z+7, r21
add r20, r24
adc r21, r1
std Z+8, r20
std Z+9, r21
ret
#endif /* CIRCULARBYTEBUFFER_NO_INIT2==0 */
/******************************************************************************/
/*
* uint8_t circularbytebuffer_cnt(circularbytebuffer_t* cb){
* return (cb->fillcount);
* }
*
* param cb: r24:r25
*/
.global circularbytebuffer_cnt
circularbytebuffer_cnt:
movw r30, r24
ldd r24, Z+FILLCOUNT_OFFSET
clr r25
ret
/******************************************************************************/
/*
* uint16_t circularbytebuffer_get_lifo(circularbytebuffer_t* cb){
* uint8_t ret;
* if(cb->fillcount==0)
* return 0xffff;
* --cb->fillcount;
* ret=*(cb->tail);
* cb->tail = (uint8_t*)(cb->tail) + 1;
* if(cb->tail>=cb->top)
* cb->tail = (uint8_t*)(cb->tail) - cb->buffer_size;
* return ret;
* }
* param cb: r24:r25
*/
.global circularbytebuffer_get_lifo
circularbytebuffer_get_lifo:
movw r30, r24
ldd r23, Z+FILLCOUNT_OFFSET
tst r23
brne 10f
ser r24
ser r25
ret
10:
dec r23
std Z+FILLCOUNT_OFFSET, r23
ldd r26, Z+TAIL_OFFSET
ldd r27, Z+TAIL_OFFSET+1
ld r24, X+
clr r25
ldd r22, Z+TOP_OFFSET
ldd r23, Z+TOP_OFFSET+1
cp r26, r22
cpc r27, r23
brlo 20f
ldd r22, Z+BUFFER_SIZE_OFFSET
sub r26, r22
sbc r27, r1
20:
std Z+TAIL_OFFSET, r26
std Z+TAIL_OFFSET+1, r27
ret
/******************************************************************************/
/*
* uint16_t circularbytebuffer_get_fifo(circularbytebuffer_t* cb){
* uint8_t ret;
* if(cb->fillcount==0)
* return 0xffff;
* --cb->fillcount;
* ret=*(cb->head);
* cb->head = (uint8_t*)(cb->head) - 1;
* if(cb->headbuffer)
* cb->head = (uint8_t*)(cb->head) + cb->buffer_size;
* return ret;
* }
*
* param cb: r24:r25
* return: r24
* modifys: r22-r27,r30,r31
*/
.global circularbytebuffer_get_fifo
circularbytebuffer_get_fifo:
movw r30, r24
ldd r23, Z+FILLCOUNT_OFFSET
tst r23
brne 10f
ser r24
ser r25
ret
10:
dec r23
std Z+FILLCOUNT_OFFSET, r23
ldd r26, Z+HEAD_OFFSET
ldd r27, Z+HEAD_OFFSET+1
ld r24, X
clr 25
sbiw r26, 1
ldd r22, Z+BUFFER_OFFSET
ldd r23, Z+BUFFER_OFFSET+1
cp r26, r22
cpc r27, r23
brge 20f
ldd r22, Z+BUFFER_SIZE_OFFSET
add r26, r22
adc r27, r1
20:
std Z+HEAD_OFFSET, r26
std Z+HEAD_OFFSET+1, r27
ret
/******************************************************************************/
/*
* uint8_t circularbytebuffer_append(uint8_t elem, circularbytebuffer_t* cb){
* if(cb->fillcount==cb->buffer_size)
* return 1;
* cb->fillcount++;
* cb->tail = cb->tail - 1;
* if(cb->tailbuffer)
* cb->tail = (uint8_t*)(cb->tail) + cb->buffer_size;
* if(cb->fillcount==1)
* cb->head = cb->tail;
* *(cb->tail) = elem;
* return 0;
* }
*
* param elem: r24
* param cb: r22:r23
*/
.global circularbytebuffer_append
circularbytebuffer_append:
movw r30, r22
ldd r22, Z+FILLCOUNT_OFFSET
ldd r23, Z+BUFFER_SIZE_OFFSET
cp r22, r23
brne 10f
ldi r24, 1
ret
10:
clt
tst r22
brne 11f
set
11:
inc r22
std Z+FILLCOUNT_OFFSET, r22
ldd r26, Z+TAIL_OFFSET
ldd r27, Z+TAIL_OFFSET+1
sbiw r26, 1
ldd r22, Z+BUFFER_OFFSET
ldd r23, Z+BUFFER_OFFSET+1
cp r26, r22
cpc r27, r23
brge 20f
ldd r22, Z+BUFFER_SIZE_OFFSET
add r26, r22
adc r27, r1
20:
std Z+TAIL_OFFSET, r26
std Z+TAIL_OFFSET+1, r27
brtc 30f
std Z+HEAD_OFFSET, r26
std Z+HEAD_OFFSET+1, r27
30:
st X, r24
clr r24
ret
/******************************************************************************/
/*
* uint8_t circularbytebuffer_push(uint8_t elem, circularbytebuffer_t* cb){
* if(cb->fillcount==cb->buffer_size)
* return 1;
* cb->fillcount++;
* cb->head = cb->head + 1;
* if(cb->head>=cb->top)
* cb->head = (uint8_t*)(cb->head) - cb->buffer_size;
* if(cb->fillcount==1)
* cb->tail = cb->head;
* *(cb->head) = elem;
* return 0;
* }
*
* param elem: r24
* param cb: r22:r23
*/
.global circularbytebuffer_push
circularbytebuffer_push:
movw r30, r22
ldd r22, Z+FILLCOUNT_OFFSET
ldd r23, Z+BUFFER_SIZE_OFFSET
cp r22, r23
brne 10f
ldi r24, 1
ret
10:
clt
tst r22
brne 11f
set
11:
inc r22
std Z+FILLCOUNT_OFFSET, r22
ldd r26, Z+HEAD_OFFSET
ldd r27, Z+HEAD_OFFSET+1
adiw r26, 1
ldd r22, Z+TOP_OFFSET
ldd r23, Z+TOP_OFFSET+1
cp r26, r22
cpc r27, r23
brlo 20f
ldd r22, Z+BUFFER_SIZE_OFFSET
sub r26, r22
sbc r27, r1
20:
std Z+HEAD_OFFSET, r26
std Z+HEAD_OFFSET+1, r27
brtc 30b
std Z+TAIL_OFFSET, r26
std Z+TAIL_OFFSET+1, r27
rjmp 30b