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