avr-crypto-lib/test_src/uart_i-asm.S

517 lines
12 KiB
ArmAsm

/* uart_i-asm.S */
/*
This file is part of the AVR-uart_i.
Copyright (C) 2006-2015 Daniel Otte (bg@nerilex.org)
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 <http://www.gnu.org/licenses/>.
*/
/**
* \file uart_i-asm.S
* \email bg@nerilex.org
* \author Daniel Otte
* \date 2009-07-24
* \license GPLv3 or later
* \ingroup uart_i
* \brief implementation of interrupt based uart
*/
#include <avr/io.h>
#include "config.h"
#include "avr-asm-macros.S"
#include "uart_defs.h"
#define XON_VALUE 0x11
#define XOFF_VALUE 0x13
#if UART0_I
#ifndef UART0_PARATY
# warning "UART0: using default paraty: 'none'"
# define UART0_PARATY UART_PARATY_NONE
#endif
#ifndef UART0_STOPBITS
# warning "UART0: using default ammount of stop bits: '1'"
# define UART0_STOPBITS UART_STOPBITS_1
#endif
#ifndef UART0_DATABITS
# warning "UART0: using default ammount of data bits: '8'"
# define UART0_DATABITS UART_DATABITS_8
#endif
#ifdef UDR
# define OLD_UART
# ifdef UDR0
# error "can not decide which registernames to use, UDR and UDR0 are defined"
# endif
#endif
#ifdef OLD_UART
# define UCSR0A UCSRA
# define UCSR0B UCSRB
# define UCSR0C UCSRC
# define UBRR0H UBRRH
# define UBRR0L UBRRL
# define UDR0 UDR
# define TXEN0 TXEN
# define RXEN0 RXEN
# define UDRE0 UDRE
# define RXC0 RXC
# define TXB80 TXB8
# define RXB80 RXB8
# define U2X0 U2X
# define UDRIE0 UDRIE
# define RXCIE0 RXCIE
#endif
#ifdef USART0_RX_vect
# define RX_ISR USART0_RX_vect
#endif
#ifdef USART_RXC_vect
# define RX_ISR USART_RXC_vect
#endif
#ifdef USART0_UDRE_vect
# define TX_ISR USART0_UDRE_vect
#endif
#ifdef USART_UDRE_vect
# define TX_ISR USART_UDRE_vect
#endif
#define CBB_SIZE 10
#define UART0_CBB_RX_OFFSET 0
#define UART0_CBB_TX_OFFSET 10
#define CTX_BASE_SIZE (2*(CBB_SIZE))
#if UART0_HOOK
# if UART0_SWFLOWCTRL
# define UART0_CTX_SIZE (3+2+CTX_BASE_SIZE)
# define UART0_HOOK_OFFSET 20
# define UART0_HOOKR_OFFSET 22
# define UART0_TXON_OFFSET 23
# define UART0_RXON_OFFSET 24
# else
# define UART0_CTX_SIZE (3+0+CTX_BASE_SIZE)
# define UART0_HOOK_OFFSET 20
# define UART0_HOOKR_OFFSET 22
# endif
#else
# if UART0_SWFLOWCTRL
# define UART0_CTX_SIZE (0+2+CTX_BASE_SIZE)
# define UART0_TXON_OFFSET 20
# define UART0_RXON_OFFSET 21
# else
# define UART0_CTX_SIZE (0+0+CTX_BASE_SIZE)
# endif
#endif
.section .bss
.global uart0_rxbuffer
uart0_rxbuffer:
.fill UART0_RXBUFFER_SIZE, 1, 0
.global uart0_txbuffer
uart0_txbuffer:
.fill UART0_TXBUFFER_SIZE, 1, 0
.global uart0_ctx
uart0_ctx:
.fill UART0_CTX_SIZE, 1, 0
/******************************************************************************/
/* Baudrate calculation */
#ifdef BAUD
#undef BAUD
#endif
#define BAUD UART0_BAUD_RATE
#include "setbaud_asm.inc"
.section .text
/******************************************************************************/
/*
* void uart0_init(void){
* circularbytebuffer_init2(UART0_RXBUFFER_SIZE, &(uart0_ctx.rxb), uart0_rxbuffer);
* circularbytebuffer_init2(UART0_TXBUFFER_SIZE, &(uart0_ctx.txb), uart0_txbuffer);
* #if UART0_HOOK
* uart0_ctx.hook = NULL;
* uart0_ctx.hook_running = 0;
* #endif
* #if UART0_SWFLOWCTRL
* uart0_ctx.txon = 1;
* uart0_ctx.rxon = 1;
* #endif
* #define BAUD UART0_BAUD_RATE
* #include <util/setbaud.h>
* UBRR0H = UBRRH_VALUE;
* UBRR0L = UBRRL_VALUE;
* #if USE_2X
* UCSR0A |= _BV(U2X0);
* #else
* UCSR0A &= ~_BV(U2X0);
* #endif
* UCSR0C = (UART0_PARATY<<4)|(UART0_STOPBITS<<3)|((UART0_DATABITS&3)<<1);
* UCSR0B = _BV(RXCIE0) | _BV(UDRIE0) | _BV(RXEN0) | _BV(TXEN0) ; / * enable TX and RX and interrupts * /
* sei();
* }
*
*/
.global uart0_init
uart0_init:
ldi r24, UART0_RXBUFFER_SIZE
clr r25
ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
ldi r20, lo8(uart0_rxbuffer)
ldi r21, hi8(uart0_rxbuffer)
rcall circularbytebuffer_init2
ldi r24, UART0_TXBUFFER_SIZE
clr r25
ldi r22, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
ldi r23, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
ldi r20, lo8(uart0_txbuffer)
ldi r21, hi8(uart0_txbuffer)
rcall circularbytebuffer_init2
#if UART0_SWFLOWCTRL
ldi r30, lo8(uart0_ctx)
ldi r31, hi8(uart0_ctx)
ldi r24, 1
std Z+UART0_TXON_OFFSET, r24
std Z+UART0_RXON_OFFSET, r24
#endif
#if UART0_HOOK
std Z+UART0_HOOK_OFFSET, r1
std Z+UART0_HOOK_OFFSET+1, r1
std Z+UART0_HOOKR_OFFSET, r1
#endif
ldi r24, UBRRH_VALUE
STORE_IO UBRR0H, r24
ldi r24, UBRRL_VALUE
STORE_IO UBRR0L, r24
#if USE_2X
SET_BIT_IO UCSR0A, U2X0, r24
#else
CLEAR_BIT_IO UCSR0A, U2X0, r24
#endif
ldi r24, (UART0_PARATY<<4)|(UART0_STOPBITS<<3)|((UART0_DATABITS&3)<<1)
STORE_IO UCSR0C, r24
ldi r24, _BV(RXCIE0) | _BV(UDRIE0) | _BV(RXEN0) | _BV(TXEN0)
STORE_IO UCSR0B, r24
sei
ret
/******************************************************************************/
/*
* ISR(USART0_UDRE_vect){
* uint16_t x;
* x = circularbytebuffer_get_fifo(&(uart0_ctx.txb));
* if(x==0xffff){
* / * the transmit buffer is empty, disable interrupt * /
* UCSR0B &= (uint8_t)~_BV(UDRIE0);
* return;
* }
* #if UART0_SWFLOWCTRL
* while(!uart0_ctx.txon)
* ;
* #endif
* UDR0 = x;
* }
*/
.global TX_ISR
TX_ISR:
push r1
push r21
push r22
in r21, _SFR_IO_ADDR(SREG)
CLEAR_BIT_IO UCSR0B, UDRIE0, r22
sei
push_range 23, 27
push_range 30, 31
clr r1
ldi r24, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
ldi r25, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
rcall circularbytebuffer_get_fifo
cpi r25, 0xff
brne 20f
CLEAR_BIT_IO UCSR0B, UDRIE0, r24
rjmp 99f
20:
#if UART0_SWFLOWCTRL
ldi r30, lo8(uart0_ctx+UART0_TXON_OFFSET)
ldi r31, hi8(uart0_ctx+UART0_TXON_OFFSET)
30:
ld r22, Z
tst r22
breq 30b
#endif
STORE_IO UDR0, r24
SET_BIT_IO UCSR0B, UDRIE0, r22
99:
ori r21, 0x80 /* set I bit */
out _SFR_IO_ADDR(SREG), r21
pop_range 30, 31
pop_range 21, 27
pop r1
ret
/******************************************************************************/
/*
* void uart0_putc (uint16_t c){
* #if UART0_SWFLOWCTRL
* while(!uart0_ctx.txon)
* ;
* #endif
* while(circularbytebuffer_cnt(&(uart0_ctx.txb))==UART0_TXBUFFER_SIZE)
* ;
* cli();
* circularbytebuffer_append((uint8_t)c, &(uart0_ctx.txb));
* sei();
* UCSR0B |= (uint8_t)_BV(UDRIE0);
* }
*
* param c: r24:r25
*/
.global uart0_putc
uart0_putc:
mov r18, r24
#if UART0_SWFLOWCTRL
ldi r30, lo8(uart0_ctx+UART0_TXON_OFFSET)
ldi r31, hi8(uart0_ctx+UART0_TXON_OFFSET)
10:
ld r22, Z
tst r22
breq 10b
#endif
ldi r26, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
ldi r27, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
20:
movw r24, r26
cli
rcall circularbytebuffer_cnt
sei
cpi r24, UART0_TXBUFFER_SIZE
breq 20b
movw r22, r26
mov r24, r18
clr r25
cli
rcall circularbytebuffer_append
SET_BIT_IO UCSR0B, UDRIE0, r24
reti
/******************************************************************************/
/*
* ISR(USART0_RX_vect){
* uint16_t c;
* c = UDR0;
* #if UART0_SWFLOWCTRL
* if(c==XON_VALUE){
* uart0_ctx.txon = 1;
* return;
* }
* if(c==XOFF_VALUE){
* uart0_ctx.txon = 0;
* return;
* }
* #endif
* #if UART0_HOOK
* if((!uart0_ctx.hook_running) && uart0_ctx.hook){
* uart0_ctx.hook_running=1;
* sei();
* do{
* uart0_ctx.hook(c);
* }while((c=circularbytebuffer_get_fifo(&(uart0_ctx.rxb)))!=0xffff);
* uart0_ctx.hook_running=0;
* return;
* }
* #endif
* if(circularbytebuffer_cnt(&(uart0_ctx.rxb))==UART0_RXBUFFER_SIZE)
* return;
* circularbytebuffer_append(c, &(uart0_ctx.rxb));
* #if UART0_SWFLOWCTRL
* if(circularbytebuffer_cnt(&(uart0_ctx.rxb))>UART0_THRESH_HIGH && uart0_ctx.rxon){
* uart0_ctx.rxon = 0;
* circularbytebuffer_push(XOFF_VALUE, &(uart0_ctx.txb));
* UCSR0B |= (uint8_t)_BV(UDRIE0);
* }
* if(circularbytebuffer_cnt(&(uart0_ctx.rxb))<UART0_THRESH_LOW && !uart0_ctx.rxon){
* uart0_ctx.rxon = 1;
* circularbytebuffer_push(XON_VALUE, &(uart0_ctx.txb));
* UCSR0B |= (uint8_t)_BV(UDRIE0);
* }
* #endif
* }
*
*/
.global RX_ISR
RX_ISR:
push_range 0, 1
push_range 16, 31
in r16, _SFR_IO_ADDR(SREG)
clr r1
LOAD_IO r24, UDR0
#if UART0_SWFLOWCTRL
ldi r26, lo8(uart0_ctx+UART0_TXON_OFFSET)
ldi r27, hi8(uart0_ctx+UART0_TXON_OFFSET)
cpi r24, XON_VALUE
breq 11f
cpi r24, XOFF_VALUE
brne 12f
clr r24
11: st X, r24
rjmp 99f
12:
push r24
/* now the "sending" part*/
ldi r24, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
ldi r25, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
rcall circularbytebuffer_cnt
ldi r30, lo8(uart0_ctx+UART0_RXON_OFFSET)
ldi r31, hi8(uart0_ctx+UART0_RXON_OFFSET)
ld r18, Z
tst r18
breq 15f/* branch if rxon inactive -> we had send an XOFF earlier */
/* ok, we did not have send an XOFF, should we? */
cpi r24, UART0_THRESH_HIGH
brlo 90f /* ok, nothing critical, go on */
st Z, r1
ldi r24, XOFF_VALUE
; sbi _SFR_IO_ADDR(PORTD), 5
rjmp 16f
15:
cpi r24, UART0_THRESH_LOW
brsh 90f /* nothing has changed */
/* if we get here, we had send an XOFF and are now below threshold */
/* so we sen an XON */
ldi r24, XON_VALUE
cbi _SFR_IO_ADDR(PORTD), 5
st Z, r24
16:
ldi r22, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
ldi r23, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
rcall circularbytebuffer_push
SET_BIT_IO UCSR0B, UDRIE0, r24
90:
pop r24
#endif /* UART0_SWFLOWCTRL */
20:
#if UART0_HOOK
ldi r30, lo8(uart0_ctx)
ldi r31, hi8(uart0_ctx)
ldd r22, Z+UART0_HOOKR_OFFSET
tst r22
brne 50f
ldd r26, Z+UART0_HOOK_OFFSET
ldd r27, Z+UART0_HOOK_OFFSET+1
adiw r26, 0
breq 50f
movw r28, r26
movw r16, r30
sei
30:
/* now we can run the hook */
movw r30, r28
clr r25
icall
movw r24, r16
rcall circularbytebuffer_get_fifo
cpi r25, 0xff
brne 30b
clr r24
st -Y, r24 /* write 0 to uart0_hook_running */
rjmp 99f
#endif /* UART0_HOOK */
50:
ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
clr r25
; sbi _SFR_IO_ADDR(PORTD), 6
rcall circularbytebuffer_append
99:
out _SFR_IO_ADDR(SREG), r16
pop_range 16, 31
pop_range 0, 1
reti
/******************************************************************************/
/*
* uint16_t uart0_getc(void){
* uint8_t ret;
* while(circularbytebuffer_cnt(&(uart0_ctx.rxb))==0)
* ;
* cli();
* ret = circularbytebuffer_get_fifo(&(uart0_ctx.rxb));
* sei();
* return ret;
* }
*/
.global uart0_getc
uart0_getc:
ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
10:
movw r24, r22
rcall circularbytebuffer_cnt
tst r24
breq 10b
movw r24, r22
cli
rcall circularbytebuffer_get_fifo
clr r25
reti
/******************************************************************************/
/*
* uint8_t uart0_dataavail(void){
* return circularbytebuffer_cnt(&(uart0_ctx.rxb));
* }
*/
.global uart0_dataavail
uart0_dataavail:
ldi r24, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
ldi r25, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
rjmp circularbytebuffer_cnt
/******************************************************************************/
#if UART0_HOOK
/*
* void uart0_sethook(void(*fpt)(uint8_t)){
* uart0_ctx.hook = fpt;
* }
*/
.global uart0_sethook
uart0_sethook:
ldi r26, lo8(uart0_ctx+UART0_HOOK_OFFSET)
ldi r27, hi8(uart0_ctx+UART0_HOOK_OFFSET)
st X+, r24
st X+, r25
ret
#endif
.global uart0_flush
uart0_flush:
10:
ldi r24, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
ldi r25, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
rcall circularbytebuffer_cnt
tst r24
brne 10b
ret
#endif /* UART0_I */