oa 2010
[aversive.git] / projects / profiling_example / main.c
1 /*  
2  *  Copyright Droids Corporation (2007)
3  *  Olivier MATZ <zer0@droids-corp.org>
4  * 
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  *  Revision : $Id: main.c,v 1.1.2.2 2007-10-28 22:31:58 zer0 Exp $
20  *
21  *
22  */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include <aversive/wait.h>
29 #include <scheduler.h>
30 #include <timer.h>
31 #include <time.h>
32 #include <uart.h>
33
34 /*
35  * The TIMER2 is used to randomly interrupt the running program and
36  * display the address of the interrupted function on the serial port.
37  *
38  * The addresses can be parsed using the python program in the same
39  * dir:
40  *    ./parse_symbols.py compiler_files/main.sym 
41  *
42  * The stdin of the python script is the list of addresses. Below is
43  * its output:
44  *
45  * 50.88% (145/285) time_wait_ms[00000b5a]
46  * 13.33% (038/285) test2[00000130]
47  * 11.23% (032/285) time_get_s[0000069e]
48  * 8.07% (023/285) main[00000156]
49  * 7.37% (021/285) test1[00000122]
50  * 4.56% (013/285) scheduler_interrupt[00000dcc]
51  * 4.56% (013/285) time_increment[000007e8]
52  */
53
54
55 #define PROFILE_TIME 10
56 volatile int a = 0;
57
58 void __attribute__ ((noinline)) dump_reg(uint16_t pc)
59 {
60         static volatile uint8_t cpt = PROFILE_TIME;
61
62         if (cpt == 1) {
63                 OCR2 = 0x80 + (rand()&0x7F);
64
65                 TCCR2 = 2;
66                 TCNT2 = 0;
67         }
68         else if (cpt == 0) {
69                 OCR2 = 0;
70                 TCCR2 = 4;
71                 TCNT2 = 0;
72                 cpt = PROFILE_TIME;
73                 printf("%.4x\n", pc);
74         }
75         cpt--;
76 }
77
78
79 void SIG_OUTPUT_COMPARE2(void) __attribute__ ((signal , naked, __INTR_ATTRS));
80
81 void SIG_OUTPUT_COMPARE2(void)
82 {
83         asm volatile("push r1" "\n\t"
84                      "push __tmp_reg__" "\n\t"
85
86                      /* save sreg */
87                      "in __tmp_reg__,__SREG__" "\n\t"
88                      "push __tmp_reg__" "\n\t"
89                      "eor r1, r1" "\n\t"
90                      
91                      /* save used regs (see avr-gcc doc about used regs) */
92                      "push r18" "\n\t"
93                      "push r19" "\n\t"
94                      "push r20" "\n\t"
95                      "push r21" "\n\t"
96                      "push r22" "\n\t"
97                      "push r23" "\n\t"
98                      "push r24" "\n\t"
99                      "push r25" "\n\t"
100                      "push r26" "\n\t"
101                      "push r27" "\n\t"
102                      "push r30" "\n\t"
103                      "push r31" "\n\t"
104                      
105                      /* load sp in r30/r31 */
106                      "in r30, __SP_L__" "\n\t"
107                      "in r31, __SP_H__" "\n\t"
108
109                      /* point to saved PC */
110                      "subi r30, lo8(-16)" "\n\t"
111                      "sbci r31, hi8(-16)" "\n\t"
112
113                      /* load Program Counter into r24-r25 */
114                      "ldd r25, Z+0" "\n\t"
115                      "ldd r24, Z+1" "\n\t"
116         
117                      /* call dump_reg, params are in r24-25 */
118                      "call dump_reg" "\n\t"
119
120                      /* restore regs */
121                      "pop r31" "\n\t"
122                      "pop r30" "\n\t"
123                      "pop r27" "\n\t"
124                      "pop r26" "\n\t"
125                      "pop r25" "\n\t"
126                      "pop r24" "\n\t"
127                      "pop r23" "\n\t"
128                      "pop r22" "\n\t"
129                      "pop r21" "\n\t"
130                      "pop r20" "\n\t"
131                      "pop r19" "\n\t"
132                      "pop r18" "\n\t"
133
134                      /* sreg */
135                      "pop __tmp_reg__" "\n\t"
136                      "out __SREG__, __tmp_reg__" "\n\t"
137         
138                      /* tmp reg */
139                      "pop __tmp_reg__" "\n\t"
140                      "pop r1" "\n\t"
141
142                      "reti" "\n\t"
143                      :
144                      :
145                      );
146 }
147
148
149 void __attribute__((noinline)) test1(void)
150 {
151         a=2;
152 }
153
154 void __attribute__((noinline)) test2(void)
155 {
156         a=1;
157         a=2;
158         a=3;
159 }
160
161 void test_sched(void * dummy)
162 {
163         time_wait_ms(50);
164 }
165
166
167 int main(void)
168 {
169         uart_init();
170         fdevopen(uart0_dev_send, uart0_dev_recv);
171         timer_init();
172         scheduler_init();
173         time_init(200);
174
175         srand(0x1337);
176         sei();
177         printf("Start profiling during 10 secs\n");
178
179         scheduler_add_periodical_event(test_sched, NULL, 100000L / SCHEDULER_UNIT);
180
181         OCR2 = 0;
182         TCNT2 = 0; 
183         TCCR2 = 4;
184         sbi(TIMSK, OCIE2);
185
186         while(time_get_s() < 10) {
187                 test1();
188                 test2();
189         };
190
191         TCCR2=0;
192         printf("Finished\n");
193         while(1);
194
195         return 0;
196 }