]> git.cryptolib.org Git - avr-crypto-lib.git/blob - test_src/uart_i-asm.S
optimizing norx32
[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 # define U2X0   U2X
75 # define UDRIE0 UDRIE
76 # define RXCIE0 RXCIE
77 #endif
78
79 #ifdef USART0_RX_vect
80 # define RX_ISR USART0_RX_vect
81 #endif
82
83 #ifdef USART_RXC_vect
84 # define RX_ISR USART_RXC_vect
85 #endif
86
87 #ifdef USART0_UDRE_vect
88 # define TX_ISR USART0_UDRE_vect
89 #endif
90
91 #ifdef USART_UDRE_vect
92 # define TX_ISR USART_UDRE_vect
93 #endif
94
95 #define CBB_SIZE 10
96
97 #define UART0_CBB_RX_OFFSET  0
98 #define UART0_CBB_TX_OFFSET 10
99
100 #define CTX_BASE_SIZE (2*(CBB_SIZE))
101
102 #if UART0_HOOK
103 #  if UART0_SWFLOWCTRL
104 #    define UART0_CTX_SIZE (3+2+CTX_BASE_SIZE)
105 #    define UART0_HOOK_OFFSET  20
106 #    define UART0_HOOKR_OFFSET 22
107 #    define UART0_TXON_OFFSET  23
108 #    define UART0_RXON_OFFSET  24
109 #  else
110 #    define UART0_CTX_SIZE (3+0+CTX_BASE_SIZE)
111 #    define UART0_HOOK_OFFSET  20
112 #    define UART0_HOOKR_OFFSET 22
113 #  endif
114 #else
115 #  if UART0_SWFLOWCTRL
116 #    define UART0_CTX_SIZE (0+2+CTX_BASE_SIZE)
117 #    define UART0_TXON_OFFSET  20
118 #    define UART0_RXON_OFFSET  21
119 #  else
120 #    define UART0_CTX_SIZE (0+0+CTX_BASE_SIZE)
121 #  endif
122 #endif
123
124         .section .bss
125 .global uart0_rxbuffer
126 uart0_rxbuffer:
127         .fill UART0_RXBUFFER_SIZE, 1, 0
128 .global uart0_txbuffer
129 uart0_txbuffer:
130         .fill UART0_TXBUFFER_SIZE, 1, 0
131 .global uart0_ctx
132 uart0_ctx:
133         .fill UART0_CTX_SIZE, 1, 0      
134 /******************************************************************************/        
135 /* Baudrate calculation */
136 #ifdef BAUD
137 #undef BAUD
138 #endif
139
140 #define BAUD UART0_BAUD_RATE
141 #include "setbaud_asm.inc"
142
143         .section .text
144 /******************************************************************************/        
145 /*
146  *      void uart0_init(void){
147  *              circularbytebuffer_init2(UART0_RXBUFFER_SIZE, &(uart0_ctx.rxb), uart0_rxbuffer);
148  *              circularbytebuffer_init2(UART0_TXBUFFER_SIZE, &(uart0_ctx.txb), uart0_txbuffer);
149  *      #if UART0_HOOK
150  *              uart0_ctx.hook = NULL;
151  *              uart0_ctx.hook_running = 0;
152  *      #endif
153  *      #if UART0_SWFLOWCTRL
154  *              uart0_ctx.txon = 1;
155  *              uart0_ctx.rxon = 1;
156  *      #endif
157  *              #define BAUD UART0_BAUD_RATE
158  *              #include <util/setbaud.h>       
159  *              UBRR0H = UBRRH_VALUE;
160  *              UBRR0L = UBRRL_VALUE;
161  *              #if USE_2X
162  *              UCSR0A |= _BV(U2X0);
163  *              #else
164  *              UCSR0A &= ~_BV(U2X0);
165  *              #endif
166  *              UCSR0C = (UART0_PARATY<<4)|(UART0_STOPBITS<<3)|((UART0_DATABITS&3)<<1);
167  *              UCSR0B = _BV(RXCIE0) | _BV(UDRIE0) | _BV(RXEN0) | _BV(TXEN0) ; / * enable TX and RX and interrupts * /
168  *              sei();
169  *      }
170  *
171  */
172 .global uart0_init
173 uart0_init:
174         ldi r24, UART0_RXBUFFER_SIZE
175         clr r25
176         ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
177         ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
178         ldi r20, lo8(uart0_rxbuffer)
179         ldi r21, hi8(uart0_rxbuffer)
180         rcall circularbytebuffer_init2
181         ldi r24, UART0_TXBUFFER_SIZE
182         clr r25
183         ldi r22, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
184         ldi r23, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
185         ldi r20, lo8(uart0_txbuffer)
186         ldi r21, hi8(uart0_txbuffer)
187         rcall circularbytebuffer_init2
188 #if UART0_SWFLOWCTRL
189         ldi r30, lo8(uart0_ctx)
190         ldi r31, hi8(uart0_ctx)
191         ldi r24, 1
192         std Z+UART0_TXON_OFFSET, r24
193         std Z+UART0_RXON_OFFSET, r24
194 #endif  
195 #if UART0_HOOK
196         std Z+UART0_HOOK_OFFSET,   r1
197         std Z+UART0_HOOK_OFFSET+1, r1
198         std Z+UART0_HOOKR_OFFSET,  r1
199 #endif
200         ldi r24, UBRRH_VALUE
201         STORE_IO UBRR0H, r24
202         ldi r24, UBRRL_VALUE
203         STORE_IO UBRR0L, r24
204 #if USE_2X
205         SET_BIT_IO UCSR0A, U2X0, r24
206 #else
207         CLEAR_BIT_IO UCSR0A, U2X0, r24
208 #endif
209         ldi r24, (UART0_PARATY<<4)|(UART0_STOPBITS<<3)|((UART0_DATABITS&3)<<1)
210         STORE_IO UCSR0C, r24
211         ldi r24, _BV(RXCIE0) | _BV(UDRIE0) | _BV(RXEN0) | _BV(TXEN0)  
212         STORE_IO UCSR0B, r24
213         sei
214         ret
215         
216 /******************************************************************************/        
217 /*
218  *      ISR(USART0_UDRE_vect){
219  *              uint16_t x;
220  *              x = circularbytebuffer_get_fifo(&(uart0_ctx.txb));
221  *              if(x==0xffff){
222  *                      / * the transmit buffer is empty, disable interrupt * /
223  *                      UCSR0B &= (uint8_t)~_BV(UDRIE0);
224  *                      return;
225  *              }
226  *      #if UART0_SWFLOWCTRL
227  *              while(!uart0_ctx.txon)
228  *                      ;
229  *      #endif          
230  *              UDR0 = x;
231  *      }
232  */ 
233  
234 .global TX_ISR
235 TX_ISR:
236         push r1
237         push r21
238         push r22
239         in r21, _SFR_IO_ADDR(SREG)
240         CLEAR_BIT_IO UCSR0B, UDRIE0, r22
241         sei
242         push_range 23, 27
243         push_range 30, 31
244         clr r1
245         ldi r24, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
246         ldi r25, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
247         rcall circularbytebuffer_get_fifo
248         cpi r25, 0xff
249         brne 20f
250         CLEAR_BIT_IO UCSR0B, UDRIE0, r24
251         rjmp 99f
252 20:
253 #if UART0_SWFLOWCTRL
254         ldi r30, lo8(uart0_ctx+UART0_TXON_OFFSET)
255         ldi r31, hi8(uart0_ctx+UART0_TXON_OFFSET)
256 30:
257         ld r22, Z
258         tst r22
259         breq 30b
260 #endif
261         STORE_IO UDR0, r24
262         SET_BIT_IO UCSR0B, UDRIE0, r22
263 99:
264         ori r21, 0x80 /* set I bit */
265         out _SFR_IO_ADDR(SREG), r21
266         pop_range 30, 31
267         pop_range 21, 27
268         pop r1
269         ret
270         
271 /******************************************************************************/
272 /*
273  *      void uart0_putc (uint16_t c){
274  *      #if UART0_SWFLOWCTRL
275  *              while(!uart0_ctx.txon)
276  *                      ;
277  *      #endif  
278  *              while(circularbytebuffer_cnt(&(uart0_ctx.txb))==UART0_TXBUFFER_SIZE)
279  *                      ;
280  *              cli();          
281  *              circularbytebuffer_append((uint8_t)c, &(uart0_ctx.txb));
282  *              sei();
283  *              UCSR0B |= (uint8_t)_BV(UDRIE0);
284  *      }
285  *
286  * param c:  r24:r25
287  */
288 .global uart0_putc
289 uart0_putc:
290         mov r18, r24
291 #if UART0_SWFLOWCTRL
292         ldi r30, lo8(uart0_ctx+UART0_TXON_OFFSET)
293         ldi r31, hi8(uart0_ctx+UART0_TXON_OFFSET)
294 10:
295         ld r22, Z
296         tst r22
297         breq 10b
298 #endif
299         ldi r26, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
300         ldi r27, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
301 20:
302         movw r24, r26
303         cli
304         rcall circularbytebuffer_cnt
305         sei
306         cpi r24, UART0_TXBUFFER_SIZE
307         breq 20b
308         movw r22, r26
309         mov r24, r18
310         clr r25
311         cli
312         rcall circularbytebuffer_append
313         SET_BIT_IO UCSR0B, UDRIE0, r24
314         reti
315
316 /******************************************************************************/
317 /*
318  *      ISR(USART0_RX_vect){
319  *              uint16_t c;
320  *              c = UDR0;
321  *      #if UART0_SWFLOWCTRL
322  *              if(c==XON_VALUE){
323  *                      uart0_ctx.txon = 1;
324  *                      return;
325  *              }
326  *              if(c==XOFF_VALUE){
327  *                      uart0_ctx.txon = 0;
328  *                      return;
329  *              }
330  *      #endif          
331  *      #if     UART0_HOOK
332  *              if((!uart0_ctx.hook_running) && uart0_ctx.hook){
333  *                      uart0_ctx.hook_running=1;
334  *                      sei();
335  *                      do{
336  *                              uart0_ctx.hook(c);
337  *                      }while((c=circularbytebuffer_get_fifo(&(uart0_ctx.rxb)))!=0xffff);
338  *                      uart0_ctx.hook_running=0;
339  *                      return;
340  *              }
341  *      #endif
342  *              if(circularbytebuffer_cnt(&(uart0_ctx.rxb))==UART0_RXBUFFER_SIZE)
343  *                      return;
344  *              circularbytebuffer_append(c, &(uart0_ctx.rxb));
345  *      #if UART0_SWFLOWCTRL
346  *              if(circularbytebuffer_cnt(&(uart0_ctx.rxb))>UART0_THRESH_HIGH && uart0_ctx.rxon){
347  *                      uart0_ctx.rxon = 0;
348  *                      circularbytebuffer_push(XOFF_VALUE, &(uart0_ctx.txb));
349  *                      UCSR0B |= (uint8_t)_BV(UDRIE0);
350  *              }
351  *              if(circularbytebuffer_cnt(&(uart0_ctx.rxb))<UART0_THRESH_LOW && !uart0_ctx.rxon){
352  *                      uart0_ctx.rxon = 1;
353  *                      circularbytebuffer_push(XON_VALUE, &(uart0_ctx.txb));
354  *                      UCSR0B |= (uint8_t)_BV(UDRIE0);
355  *              }
356  *      #endif          
357  *      }
358  *
359  */
360  .global RX_ISR
361  RX_ISR:
362         push_range 0, 1
363         push_range 16, 31
364         in r16, _SFR_IO_ADDR(SREG)
365         clr r1
366         LOAD_IO r24, UDR0
367 #if UART0_SWFLOWCTRL
368     ldi r26, lo8(uart0_ctx+UART0_TXON_OFFSET)
369         ldi r27, hi8(uart0_ctx+UART0_TXON_OFFSET)
370         cpi r24, XON_VALUE
371         breq 11f
372         cpi r24, XOFF_VALUE
373         brne 12f
374         clr r24
375 11:     st X, r24
376         rjmp 99f
377 12:
378         push r24
379 /* now the "sending" part*/
380         ldi r24, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
381         ldi r25, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
382         rcall circularbytebuffer_cnt
383         ldi r30, lo8(uart0_ctx+UART0_RXON_OFFSET)
384         ldi r31, hi8(uart0_ctx+UART0_RXON_OFFSET)
385         ld r18, Z
386         tst r18
387         breq 15f/* branch if rxon inactive -> we had send an XOFF earlier */
388         /* ok, we did not have send an XOFF, should we? */
389         cpi r24, UART0_THRESH_HIGH
390         brlo 90f /* ok, nothing critical, go on */
391         st Z, r1
392         ldi r24, XOFF_VALUE
393 ;       sbi _SFR_IO_ADDR(PORTD), 5
394         rjmp 16f
395 15:
396         cpi r24, UART0_THRESH_LOW
397         brsh 90f /* nothing has changed */
398         /* if we get here, we had send an XOFF and are now below threshold */
399         /* so we sen an XON */
400         ldi r24, XON_VALUE
401         cbi _SFR_IO_ADDR(PORTD), 5
402         st Z, r24
403 16:
404         ldi r22, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
405         ldi r23, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
406         rcall circularbytebuffer_push
407         SET_BIT_IO UCSR0B, UDRIE0, r24
408 90:
409         pop r24
410 #endif /* UART0_SWFLOWCTRL */   
411 20:     
412 #if UART0_HOOK
413         ldi r30, lo8(uart0_ctx)
414         ldi r31, hi8(uart0_ctx)
415         ldd r22, Z+UART0_HOOKR_OFFSET
416         tst r22
417         brne 50f
418         ldd r26, Z+UART0_HOOK_OFFSET
419         ldd r27, Z+UART0_HOOK_OFFSET+1
420         adiw r26, 0
421         breq 50f
422         movw r28, r26
423         movw r16, r30
424         sei
425 30:
426         /* now we can run the hook */
427         movw r30, r28
428         clr r25
429         icall
430         movw r24, r16
431         rcall circularbytebuffer_get_fifo 
432         cpi r25, 0xff
433         brne 30b
434         clr r24
435         st -Y, r24 /* write 0 to uart0_hook_running */
436         rjmp 99f
437 #endif /* UART0_HOOK */
438 50:
439         ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
440         ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
441         clr r25
442 ;       sbi _SFR_IO_ADDR(PORTD), 6
443         rcall circularbytebuffer_append
444 99:     
445         out _SFR_IO_ADDR(SREG), r16
446         pop_range 16, 31
447         pop_range 0, 1
448         reti
449
450 /******************************************************************************/
451 /*
452  *      uint16_t uart0_getc(void){
453  *              uint8_t ret;
454  *              while(circularbytebuffer_cnt(&(uart0_ctx.rxb))==0)
455  *                      ;
456  *              cli();  
457  *              ret = circularbytebuffer_get_fifo(&(uart0_ctx.rxb));
458  *              sei();
459  *              return  ret;
460  *      }
461  */
462  .global uart0_getc
463  uart0_getc:
464         ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
465         ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
466  10:
467         movw r24, r22
468         rcall circularbytebuffer_cnt
469         tst r24
470         breq 10b
471         movw r24, r22
472         cli
473         rcall circularbytebuffer_get_fifo
474         clr r25
475         reti
476         
477 /******************************************************************************/
478 /*
479  *      uint8_t uart0_dataavail(void){
480  *              return circularbytebuffer_cnt(&(uart0_ctx.rxb));
481  *      }
482  */
483 .global uart0_dataavail
484 uart0_dataavail:
485         ldi r24, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
486         ldi r25, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
487         rjmp circularbytebuffer_cnt
488         
489 /******************************************************************************/
490 #if     UART0_HOOK
491 /*
492  *      void uart0_sethook(void(*fpt)(uint8_t)){
493  *              uart0_ctx.hook = fpt;
494  *      }
495  */
496 .global uart0_sethook
497 uart0_sethook:
498         ldi r26, lo8(uart0_ctx+UART0_HOOK_OFFSET)
499         ldi r27, hi8(uart0_ctx+UART0_HOOK_OFFSET)
500         st X+, r24
501         st X+, r25
502         ret
503 #endif
504
505 .global uart0_flush
506 uart0_flush:
507 10:
508         ldi r24, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
509         ldi r25, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
510         rcall circularbytebuffer_cnt
511         tst r24
512         brne 10b
513         ret
514
515         
516 #endif /* UART0_I */