]> git.cryptolib.org Git - avr-crypto-lib.git/blobdiff - test_src/uart_i-asm.S
backporting uart_i and cli
[avr-crypto-lib.git] / test_src / uart_i-asm.S
diff --git a/test_src/uart_i-asm.S b/test_src/uart_i-asm.S
new file mode 100644 (file)
index 0000000..8ce866b
--- /dev/null
@@ -0,0 +1,447 @@
+/* uart_i-asm.S */
+/*
+    This file is part of the AVR-uart_i.
+    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 <http://www.gnu.org/licenses/>.
+*/
+/**
+ * \file     uart_i-asm.S
+ * \email    daniel.otte@rub.de
+ * \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"
+
+#define XON_VALUE  0x11
+#define XOFF_VALUE 0x13
+
+#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
+#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 r24, UART0_RXBUFFER_SIZE
+       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 r24, UART0_TXBUFFER_SIZE
+       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 
+       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
+/*                  UCSR0A */
+#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 USART0_UDRE_vect
+USART0_UDRE_vect:
+       push_range 21, 26
+       push_range 30, 31
+       in r21, _SFR_IO_ADDR(SREG)
+       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
+99:
+       out _SFR_IO_ADDR(SREG), r21
+       pop_range 30, 31
+       pop_range 21, 26
+       reti
+       
+/******************************************************************************/
+/*
+ *     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
+       rcall circularbytebuffer_cnt
+       cpi r24, UART0_TXBUFFER_SIZE
+       breq 20b
+       movw r22, r26
+       mov r24, r18
+       clr r25
+       cli
+       rcall circularbytebuffer_append
+       sei
+       SET_BIT_IO UCSR0B, UDRIE0, r24
+       ret
+
+/******************************************************************************/
+/*
+ *     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 USART0_RX_vect
+ USART0_RX_vect:
+       push_range 16, 31
+       in r21, _SFR_IO_ADDR(SREG)
+       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
+       brne 10f
+       ldi r24, 1
+       st X, r24
+       rjmp 99f
+10:    
+       cpi r24, XOFF_VALUE
+       brne 20f
+       clr r24
+       st X, r24
+       rjmp 99f
+#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
+       rcall circularbytebuffer_append
+#if UART0_SWFLOWCTRL
+       ldi r24, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
+       ldi r25, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
+       rcall circularbytebuffer_cnt
+       ldi r22, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
+       ldi r23, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
+       ldi r30, lo8(uart0_ctx+UART0_RXON_OFFSET)
+       ldi r31, hi8(uart0_ctx+UART0_RXON_OFFSET)
+       ld r21, Z
+       tst r21
+       breq 60f
+       cpi r24, UART0_THRESH_HIGH+1
+       brlo 99f
+       clr r25
+       ldi r24, XOFF_VALUE
+       rcall circularbytebuffer_push
+       SET_BIT_IO UCSR0B, UDRIE0, r24
+       rjmp 99f
+60:
+       cpi r24, UART0_THRESH_LOW
+       brge 99f
+       clr r25
+       ldi r24, XON_VALUE
+       rcall circularbytebuffer_push
+       SET_BIT_IO UCSR0B, UDRIE0, r24
+#endif /* UART0_SWFLOWCTRL */
+99:    
+       out _SFR_IO_ADDR(SREG), r21
+       pop_range 16, 31
+       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
+       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
+