]> git.cryptolib.org Git - avr-crypto-lib.git/blob - test_src/uart_i-asm.S
backporting uart_i and cli
[avr-crypto-lib.git] / test_src / uart_i-asm.S
1 /* uart_i-asm.S */
2 /*
3     This file is part of the AVR-uart_i.
4     Copyright (C) 2009  Daniel Otte (daniel.otte@rub.de)
5
6     This program is free software: you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation, either version 3 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 /**
20  * \file     uart_i-asm.S
21  * \email    daniel.otte@rub.de
22  * \author   Daniel Otte 
23  * \date     2009-07-24
24  * \license  GPLv3 or later
25  * \ingroup  uart_i
26  * \brief    implementation of interrupt based uart
27  */
28
29 #include <avr/io.h>
30 #include "config.h"
31 #include "avr-asm-macros.S"
32
33 #define XON_VALUE  0x11
34 #define XOFF_VALUE 0x13
35
36 #ifdef UDR
37 # define OLD_UART
38 # ifdef UDR0
39 #  error "can not decide which registernames to use, UDR and UDR0 are defined"
40 # endif
41 #endif
42
43 #ifdef OLD_UART
44 # define UCSR0A UCSRA
45 # define UCSR0B UCSRB
46 # define UCSR0C UCSRC
47 # define UBRR0H UBRRH
48 # define UBRR0L UBRRL
49 # define UDR0   UDR
50 # define TXEN0  TXEN
51 # define RXEN0  RXEN
52 # define UDRE0  UDRE
53 # define RXC0   RXC
54 # define TXB80  TXB8
55 # define RXB80  RXB8
56 #endif
57
58 #define CBB_SIZE 10
59
60 #define UART0_CBB_RX_OFFSET  0
61 #define UART0_CBB_TX_OFFSET 10
62
63 #define CTX_BASE_SIZE (2*(CBB_SIZE))
64
65 #if UART0_HOOK
66 #  if UART0_SWFLOWCTRL
67 #    define UART0_CTX_SIZE (3+2+CTX_BASE_SIZE)
68 #    define UART0_HOOK_OFFSET  20
69 #    define UART0_HOOKR_OFFSET 22
70 #    define UART0_TXON_OFFSET  23
71 #    define UART0_RXON_OFFSET  24
72 #  else
73 #    define UART0_CTX_SIZE (3+0+CTX_BASE_SIZE)
74 #    define UART0_HOOK_OFFSET  20
75 #    define UART0_HOOKR_OFFSET 22
76 #  endif
77 #else
78 #  if UART0_SWFLOWCTRL
79 #    define UART0_CTX_SIZE (0+2+CTX_BASE_SIZE)
80 #    define UART0_TXON_OFFSET  20
81 #    define UART0_RXON_OFFSET  21
82 #  else
83 #    define UART0_CTX_SIZE (0+0+CTX_BASE_SIZE)
84 #  endif
85 #endif
86
87         .section .bss
88 .global uart0_rxbuffer
89 uart0_rxbuffer:
90         .fill UART0_RXBUFFER_SIZE, 1, 0
91 .global uart0_txbuffer
92 uart0_txbuffer:
93         .fill UART0_TXBUFFER_SIZE, 1, 0
94 .global uart0_ctx
95 uart0_ctx:
96         .fill UART0_CTX_SIZE, 1, 0      
97 /******************************************************************************/        
98 /* Baudrate calculation */
99 #ifdef BAUD
100 #undef BAUD
101 #endif
102
103 #define BAUD UART0_BAUD_RATE
104 #include "setbaud_asm.inc"
105
106         .section .text
107 /******************************************************************************/        
108 /*
109  *      void uart0_init(void){
110  *              circularbytebuffer_init2(UART0_RXBUFFER_SIZE, &(uart0_ctx.rxb), uart0_rxbuffer);
111  *              circularbytebuffer_init2(UART0_TXBUFFER_SIZE, &(uart0_ctx.txb), uart0_txbuffer);
112  *      #if UART0_HOOK
113  *              uart0_ctx.hook = NULL;
114  *              uart0_ctx.hook_running = 0;
115  *      #endif
116  *      #if UART0_SWFLOWCTRL
117  *              uart0_ctx.txon = 1;
118  *              uart0_ctx.rxon = 1;
119  *      #endif
120  *              #define BAUD UART0_BAUD_RATE
121  *              #include <util/setbaud.h>       
122  *              UBRR0H = UBRRH_VALUE;
123  *              UBRR0L = UBRRL_VALUE;
124  *              #if USE_2X
125  *              UCSR0A |= _BV(U2X0);
126  *              #else
127  *              UCSR0A &= ~_BV(U2X0);
128  *              #endif
129  *              UCSR0C = (UART0_PARATY<<4)|(UART0_STOPBITS<<3)|((UART0_DATABITS&3)<<1);
130  *              UCSR0B = _BV(RXCIE0) | _BV(UDRIE0) | _BV(RXEN0) | _BV(TXEN0) ; / * enable TX and RX and interrupts * /
131  *              sei();
132  *      }
133  *
134  */
135 .global uart0_init
136 uart0_init:
137         ldi r24, UART0_RXBUFFER_SIZE
138         clr r25
139         ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
140         ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
141         ldi r24, UART0_RXBUFFER_SIZE
142         ldi r20, lo8(uart0_rxbuffer)
143         ldi r21, hi8(uart0_rxbuffer)
144         rcall circularbytebuffer_init2
145         ldi r24, UART0_TXBUFFER_SIZE
146         clr r25
147         ldi r22, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
148         ldi r23, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
149         ldi r24, UART0_TXBUFFER_SIZE
150         ldi r20, lo8(uart0_txbuffer)
151         ldi r21, hi8(uart0_txbuffer)
152         rcall circularbytebuffer_init2
153 #if UART0_SWFLOWCTRL
154         ldi r30, lo8(uart0_ctx)
155         ldi r31, hi8(uart0_ctx)
156         ldi r24, 1
157         std Z+UART0_TXON_OFFSET, r24
158         std Z+UART0_RXON_OFFSET, r24
159 #endif  
160         ldi r24, UBRRH_VALUE
161         STORE_IO UBRR0H, r24
162         ldi r24, UBRRL_VALUE
163         STORE_IO UBRR0L, r24
164 #if USE_2X
165         SET_BIT_IO UCSR0A, U2X0, r24
166 #else
167         CLEAR_BIT_IO UCSR0A, U2X0, r24
168 /*                   UCSR0A */
169 #endif
170         ldi r24, (UART0_PARATY<<4)|(UART0_STOPBITS<<3)|((UART0_DATABITS&3)<<1)
171         STORE_IO UCSR0C, r24
172         ldi r24, _BV(RXCIE0) | _BV(UDRIE0) | _BV(RXEN0) | _BV(TXEN0)  
173         STORE_IO UCSR0B, r24
174         sei
175         ret
176         
177 /******************************************************************************/        
178 /*
179  *      ISR(USART0_UDRE_vect){
180  *              uint16_t x;
181  *              x = circularbytebuffer_get_fifo(&(uart0_ctx.txb));
182  *              if(x==0xffff){
183  *                      / * the transmit buffer is empty, disable interrupt * /
184  *                      UCSR0B &= (uint8_t)~_BV(UDRIE0);
185  *                      return;
186  *              }
187  *      #if UART0_SWFLOWCTRL
188  *              while(!uart0_ctx.txon)
189  *                      ;
190  *      #endif          
191  *              UDR0 = x;
192  *      }
193  */ 
194  
195 .global USART0_UDRE_vect
196 USART0_UDRE_vect:
197         push_range 21, 26
198         push_range 30, 31
199         in r21, _SFR_IO_ADDR(SREG)
200         ldi r24, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
201         ldi r25, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
202         rcall circularbytebuffer_get_fifo
203         cpi r25, 0xff
204         brne 20f
205         CLEAR_BIT_IO UCSR0B, UDRIE0, r24
206         rjmp 99f
207 20:
208 #if UART0_SWFLOWCTRL
209         ldi r30, lo8(uart0_ctx+UART0_TXON_OFFSET)
210         ldi r31, hi8(uart0_ctx+UART0_TXON_OFFSET)
211 30:
212         ld r22, Z
213         tst r22
214         breq 30b
215 #endif
216         STORE_IO UDR0, r24
217 99:
218         out _SFR_IO_ADDR(SREG), r21
219         pop_range 30, 31
220         pop_range 21, 26
221         reti
222         
223 /******************************************************************************/
224 /*
225  *      void uart0_putc (uint16_t c){
226  *      #if UART0_SWFLOWCTRL
227  *              while(!uart0_ctx.txon)
228  *                      ;
229  *      #endif  
230  *              while(circularbytebuffer_cnt(&(uart0_ctx.txb))==UART0_TXBUFFER_SIZE)
231  *                      ;
232  *              cli();          
233  *              circularbytebuffer_append((uint8_t)c, &(uart0_ctx.txb));
234  *              sei();
235  *              UCSR0B |= (uint8_t)_BV(UDRIE0);
236  *      }
237  *
238  * param c:  r24:r25
239  */
240 .global uart0_putc
241 uart0_putc:
242         mov r18, r24
243 #if UART0_SWFLOWCTRL
244         ldi r30, lo8(uart0_ctx+UART0_TXON_OFFSET)
245         ldi r31, hi8(uart0_ctx+UART0_TXON_OFFSET)
246 10:
247         ld r22, Z
248         tst r22
249         breq 10b
250 #endif
251         ldi r26, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
252         ldi r27, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
253 20:
254         movw r24, r26
255         rcall circularbytebuffer_cnt
256         cpi r24, UART0_TXBUFFER_SIZE
257         breq 20b
258         movw r22, r26
259         mov r24, r18
260         clr r25
261         cli
262         rcall circularbytebuffer_append
263         sei
264         SET_BIT_IO UCSR0B, UDRIE0, r24
265         ret
266
267 /******************************************************************************/
268 /*
269  *      ISR(USART0_RX_vect){
270  *              uint16_t c;
271  *              c = UDR0;
272  *      #if UART0_SWFLOWCTRL
273  *              if(c==XON_VALUE){
274  *                      uart0_ctx.txon = 1;
275  *                      return;
276  *              }
277  *              if(c==XOFF_VALUE){
278  *                      uart0_ctx.txon = 0;
279  *                      return;
280  *              }
281  *      #endif          
282  *      #if     UART0_HOOK
283  *              if((!uart0_ctx.hook_running) && uart0_ctx.hook){
284  *                      uart0_ctx.hook_running=1;
285  *                      sei();
286  *                      do{
287  *                              uart0_ctx.hook(c);
288  *                      }while((c=circularbytebuffer_get_fifo(&(uart0_ctx.rxb)))!=0xffff);
289  *                      uart0_ctx.hook_running=0;
290  *                      return;
291  *              }
292  *      #endif
293  *              if(circularbytebuffer_cnt(&(uart0_ctx.rxb))==UART0_RXBUFFER_SIZE)
294  *                      return;
295  *              circularbytebuffer_append(c, &(uart0_ctx.rxb));
296  *      #if UART0_SWFLOWCTRL
297  *              if(circularbytebuffer_cnt(&(uart0_ctx.rxb))>UART0_THRESH_HIGH && uart0_ctx.rxon){
298  *                      uart0_ctx.rxon = 0;
299  *                      circularbytebuffer_push(XOFF_VALUE, &(uart0_ctx.txb));
300  *                      UCSR0B |= (uint8_t)_BV(UDRIE0);
301  *              }
302  *              if(circularbytebuffer_cnt(&(uart0_ctx.rxb))<UART0_THRESH_LOW && !uart0_ctx.rxon){
303  *                      uart0_ctx.rxon = 1;
304  *                      circularbytebuffer_push(XON_VALUE, &(uart0_ctx.txb));
305  *                      UCSR0B |= (uint8_t)_BV(UDRIE0);
306  *              }
307  *      #endif          
308  *      }
309  *
310  */
311  .global USART0_RX_vect
312  USART0_RX_vect:
313         push_range 16, 31
314         in r21, _SFR_IO_ADDR(SREG)
315         LOAD_IO r24, UDR0
316 #if UART0_SWFLOWCTRL
317         ldi r26, lo8(uart0_ctx+UART0_TXON_OFFSET)
318         ldi r27, hi8(uart0_ctx+UART0_TXON_OFFSET)
319         cpi r24, XON_VALUE
320         brne 10f
321         ldi r24, 1
322         st X, r24
323         rjmp 99f
324 10:     
325         cpi r24, XOFF_VALUE
326         brne 20f
327         clr r24
328         st X, r24
329         rjmp 99f
330 #endif /* UART0_SWFLOWCTRL */   
331 20:     
332 #if UART0_HOOK
333         ldi r30, lo8(uart0_ctx)
334         ldi r31, hi8(uart0_ctx)
335         ldd r22, Z+UART0_HOOKR_OFFSET
336         tst r22
337         brne 50f
338         ldd r26, Z+UART0_HOOK_OFFSET
339         ldd r27, Z+UART0_HOOK_OFFSET+1
340         adiw r26, 0
341         breq 50f
342         movw r28, r26
343         movw r16, r30
344         sei
345 30:
346         /* now we can run the hook */
347         movw r30, r28
348         clr r25
349         icall
350         movw r24, r16
351         rcall circularbytebuffer_get_fifo 
352         cpi r25, 0xff
353         brne 30b
354         clr r24
355         st -Y, r24 /* write 0 to uart0_hook_running */
356         rjmp 99f
357 #endif /* UART0_HOOK */
358 50:
359         ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
360         ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
361         clr r25
362         rcall circularbytebuffer_append
363 #if UART0_SWFLOWCTRL
364         ldi r24, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
365         ldi r25, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
366         rcall circularbytebuffer_cnt
367         ldi r22, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
368         ldi r23, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
369         ldi r30, lo8(uart0_ctx+UART0_RXON_OFFSET)
370         ldi r31, hi8(uart0_ctx+UART0_RXON_OFFSET)
371         ld r21, Z
372         tst r21
373         breq 60f
374         cpi r24, UART0_THRESH_HIGH+1
375         brlo 99f
376         clr r25
377         ldi r24, XOFF_VALUE
378         rcall circularbytebuffer_push
379         SET_BIT_IO UCSR0B, UDRIE0, r24
380         rjmp 99f
381 60:
382         cpi r24, UART0_THRESH_LOW
383         brge 99f
384         clr r25
385         ldi r24, XON_VALUE
386         rcall circularbytebuffer_push
387         SET_BIT_IO UCSR0B, UDRIE0, r24
388 #endif /* UART0_SWFLOWCTRL */
389 99:     
390         out _SFR_IO_ADDR(SREG), r21
391         pop_range 16, 31
392         reti
393
394 /******************************************************************************/
395 /*
396  *      uint16_t uart0_getc(void){
397  *              uint8_t ret;
398  *              while(circularbytebuffer_cnt(&(uart0_ctx.rxb))==0)
399  *                      ;
400  *              cli();  
401  *              ret = circularbytebuffer_get_fifo(&(uart0_ctx.rxb));
402  *              sei();
403  *              return  ret;
404  *      }
405  */
406  .global uart0_getc
407  uart0_getc:
408         ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
409         ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
410  10:
411         movw r24, r22
412         rcall circularbytebuffer_cnt
413         tst r24
414         breq 10b
415         movw r24, r22
416         cli
417         rcall circularbytebuffer_get_fifo
418         reti
419         
420 /******************************************************************************/
421 /*
422  *      uint8_t uart0_dataavail(void){
423  *              return circularbytebuffer_cnt(&(uart0_ctx.rxb));
424  *      }
425  */
426 .global uart0_dataavail
427 uart0_dataavail:
428         ldi r24, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
429         ldi r25, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
430         rjmp circularbytebuffer_cnt
431         
432 /******************************************************************************/
433 #if     UART0_HOOK
434 /*
435  *      void uart0_sethook(void(*fpt)(uint8_t)){
436  *              uart0_ctx.hook = fpt;
437  *      }
438  */
439 .global uart0_sethook
440 uart0_sethook:
441         ldi r26, lo8(uart0_ctx+UART0_HOOK_OFFSET)
442         ldi r27, hi8(uart0_ctx+UART0_HOOK_OFFSET)
443         st X+, r24
444         st X+, r25
445         ret
446 #endif
447