Aggiornato il comment block dei log RCS
[bertos.git] / drv / kdebug.c
1 /*!
2  * \file
3  * <!--
4  * Copyright 2003,2004 Develer S.r.l. (http://www.develer.com/)
5  * Copyright 2000,2001,2002 Bernardo Innocenti <bernie@codewiz.org>
6  * This file is part of DevLib - See devlib/README for information.
7  * -->
8  *
9  * \brief General pourpose debug functions.
10  *
11  * \version $Id$
12  *
13  * \author Bernardo Innocenti <bernie@develer.com>
14  * \author Stefano Fedrigo <aleph@develer.com>
15  */
16
17 /*#*
18  *#* $Log$
19  *#* Revision 1.12  2004/08/25 14:12:08  rasky
20  *#* Aggiornato il comment block dei log RCS
21  *#*
22  *#* Revision 1.11  2004/08/24 16:19:08  bernie
23  *#* kputchar(): New public function; Add missing dummy inlines for \!_DEBUG.
24  *#*
25  *#* Revision 1.10  2004/08/04 15:57:50  rasky
26  *#* Cambiata la putchar per kdebug per DSP56k: la nuova funzione e' quella piu' a basso livello (assembly)
27  *#*
28  *#* Revision 1.9  2004/08/02 20:20:29  aleph
29  *#* Merge from project_ks
30  *#*
31  *#* Revision 1.8  2004/07/30 14:26:33  rasky
32  *#* Semplificato l'output dell'ASSERT
33  *#* Aggiunta ASSERT2 con stringa di help opzionalmente disattivabile
34  *#*
35  *#* Revision 1.7  2004/07/30 14:15:53  rasky
36  *#* Nuovo supporto unificato per detect della CPU
37  *#*
38  *#* Revision 1.6  2004/07/18 21:49:28  bernie
39  *#* Add ATmega8 support.
40  *#*
41  *#* Revision 1.5  2004/06/27 15:20:26  aleph
42  *#* Change UNUSED() macro to accept two arguments: type and name;
43  *#* Add macro GNUC_PREREQ to detect GCC version during build;
44  *#* Some spacing cleanups and typo fix
45  *#*
46  *#* Revision 1.4  2004/06/06 18:09:51  bernie
47  *#* Import DSP56800 changes; Print broken wall bricks in hex.
48  *#*
49  *#* Revision 1.3  2004/06/03 11:27:09  bernie
50  *#* Add dual-license information.
51  *#*
52  *#* Revision 1.2  2004/05/23 18:21:53  bernie
53  *#* Trim CVS logs and cleanup header info.
54  *#*
55  *#*/
56
57 #include "kdebug.h"
58 #include "hw.h"
59 #include "config.h"
60
61 #include <mware/formatwr.h> /* for _formatted_write() */
62
63 #ifdef _DEBUG
64
65 #if defined(_EMUL)
66         #include <stdio.h>
67         #define KDBG_WAIT_READY()      do { /*nop*/ } while(0)
68         #define KDBG_WRITE_CHAR(c)     putchar((c))
69         #define KDBG_MASK_IRQ(old)     do { (void)(old); } while(0)
70         #define KDBG_RESTORE_IRQ()     do { /*nop*/ } while(0)
71         typedef kdbg_irqsave_t         char; /* unused */
72 #elif CPU_I196
73         #include "Util196.h"
74         #define KDBG_WAIT_READY()      do {} while (!(SP_STAT & (SPSF_TX_EMPTY | SPSF_TX_INT)))
75         #define KDBG_WRITE_CHAR(c)     do { SBUF = (c); } while(0)
76         #define KDBG_MASK_IRQ(old) \
77                 do { \
78                         (old) = INT_MASK1 & INT1F_TI; \
79                         INT_MASK1 &= ~INT1F_TI; \
80                 } while(0)
81         #define KDBG_RESTORE_IRQ(old)  do { INT_MASK1 |= (old); }
82         typedef kdbg_irqsave_t         uint16_t; /* FIXME: unconfirmed */
83 #elif CPU_AVR
84         #include <avr/io.h>
85         #if CONFIG_KDEBUG_PORT == 0
86
87                 /* External 485 transceiver on UART0 (to be overridden in "hw.h").  */
88                 #if !defined(SER_UART0_485_INIT)
89                         #if defined(SER_UART0_485_RX) || defined(SER_UART0_485_TX)
90                                 #error SER_UART0_485_INIT, SER_UART0_485_RX and SER_UART0_485_TX must be defined together
91                         #endif
92                         #define SER_UART0_485_INIT  do {} while (0)
93                         #define SER_UART0_485_TX    do {} while (0)
94                         #define SER_UART0_485_RX    do {} while (0)
95                 #elif !defined(SER_UART0_485_RX) || !defined(SER_UART0_485_TX)
96                         #error SER_UART0_485_INIT, SER_UART0_485_RX and SER_UART0_485_TX must be defined together
97                 #endif
98
99                 #if defined(__AVR_ATmega64__)
100                         #define UCR UCSR0B
101                         #define UDR UDR0
102                         #define USR UCSR0A
103                 #elif defined(__AVR_ATmega8__)
104                         #define UCR UCSRB
105                         #define USR UCSRA
106                 #endif
107
108                 #define KDBG_WAIT_READY()     do { loop_until_bit_is_set(USR, UDRE); } while(0)
109                 #define KDBG_WAIT_TXDONE()    do { loop_until_bit_is_set(USR, TXC); } while(0)
110                 /*
111                  * BUG: before sending a new character the TXC flag is cleared to allow
112                  * KDBG_WAIT_TXDONE() to work properly, but, if KDBG_WRITE_CHAR() is called
113                  * after the RXC flag is set by hardware, a new TXC could be generated
114                  * after we clear it and before the new character is put in UDR. In this
115                  * case if a 485 is used the transceiver will be put in RX mode while
116                  * transmitting the last char.
117                  */
118                 #define KDBG_WRITE_CHAR(c)    do { USR |= BV(TXC); UDR = (c); } while(0)
119
120                 #define KDBG_MASK_IRQ(old)    do { \
121                         SER_UART0_485_TX; \
122                         (old) = UCR; \
123                         UCR |= BV(TXEN); \
124                         UCR &= ~(BV(TXCIE) | BV(UDRIE)); \
125                 } while(0)
126
127                 #define KDBG_RESTORE_IRQ(old) do { \
128                         KDBG_WAIT_TXDONE(); \
129                         SER_UART0_485_RX; \
130                         UCR = (old); \
131                 } while(0)
132
133                 typedef kdbg_irqsave_t uint8_t;
134
135         #elif CONFIG_KDEBUG_PORT == 1
136
137                 /* External 485 transceiver on UART1 (to be overridden in "hw.h").  */
138                 #ifndef SER_UART1_485_INIT
139                         #if defined(SER_UART1_485_RX) || defined(SER_UART1_485_TX)
140                                 #error SER_UART1_485_INIT, SER_UART1_485_RX and SER_UART1_485_TX must be defined together
141                         #endif
142                         #define SER_UART1_485_INIT  do {} while (0)
143                         #define SER_UART1_485_TX    do {} while (0)
144                         #define SER_UART1_485_RX    do {} while (0)
145                 #elif !defined(SER_UART1_485_RX) || !defined(SER_UART1_485_TX)
146                         #error SER_UART1_485_INIT, SER_UART1_485_RX and SER_UART1_485_TX must be defined together
147                 #endif
148
149                 #define KDBG_WAIT_READY()     do { loop_until_bit_is_set(UCSR1A, UDRE); } while(0)
150                 #define KDBG_WAIT_TXDONE()    do { loop_until_bit_is_set(UCSR1A, TXC); } while(0)
151                 #define KDBG_WRITE_CHAR(c)    do { UCSR1A |= BV(TXC); UDR1 = (c); } while(0)
152
153                 #define KDBG_MASK_IRQ(old)    do { \
154                         SER_UART1_485_TX; \
155                         (old) = UCSR1B; \
156                         UCSR1B |= BV(TXEN); \
157                         UCSR1B &= ~(BV(TXCIE) | BV(UDRIE)); \
158                 } while(0)
159
160                 #define KDBG_RESTORE_IRQ(old) do { \
161                         KDBG_WAIT_TXDONE(); \
162                         SER_UART1_485_RX; \
163                         UCSR1B = (old); \
164                 } while(0)
165
166                 typedef kdbg_irqsave_t uint8_t;
167         #else
168                 #error CONFIG_KDEBUG_PORT should be either 0 or 1
169         #endif
170 #elif defined(__MWERKS__) && CPU_DSP56K
171         /* Debugging go through the JTAG interface. The MSL library already
172            implements the console I/O correctly. */
173         #include <stdio.h>
174         #define KDBG_WAIT_READY()         do { } while (0)
175         #define KDBG_WRITE_CHAR(c)        __put_char(c, stdout)
176         #define KDBG_MASK_IRQ(old)        do { (void)(old); } while (0)
177         #define KDBG_RESTORE_IRQ(old)     do { (void)(old); } while (0)
178         typedef kdbg_irqsave_t            uint8_t; /* unused */
179 #else
180         #error Unknown architecture
181 #endif
182
183
184 void kdbg_init(void)
185 {
186 #if CPU_I196
187
188         /* Set serial port for 19200bps 8N1 */
189         INT_MASK1 &= ~(INT1F_TI | INT1F_RI);
190         SP_CON = SPCF_RECEIVE_ENABLE | SPCF_MODE1;
191         ioc1_img |= IOC1F_TXD_SEL | IOC1F_EXTINT_SRC;
192         IOC1 = ioc1_img;
193         BAUD_RATE = 0x33;
194         BAUD_RATE = 0x80;
195
196 #elif CPU_AVR
197
198         /* Compute the baud rate */
199         uint16_t period = (((CLOCK_FREQ / 16UL) + (CONFIG_KDEBUG_BAUDRATE / 2)) / CONFIG_KDEBUG_BAUDRATE) - 1;
200
201         #if defined(__AVR_ATmega64__)
202                 #if CONFIG_KDEBUG_PORT == 0
203                         UBRR0H = (uint8_t)(period>>8);
204                         UBRR0L = (uint8_t)period;
205                         SER_UART0_485_INIT;
206                 #elif CONFIG_KDEBUG_PORT == 1
207                         UBRR1H = (uint8_t)(period>>8);
208                         UBRR1L = (uint8_t)period;
209                         SER_UART1_485_INIT;
210                 #else
211                         #error CONFIG_KDEBUG_PORT must be either 0 or 1
212                 #endif
213         #elif defined(__AVR_ATmega8__)
214                 UBRRH = (uint8_t)(period>>8);
215                 UBRRL = (uint8_t)period;
216         #elif defined(__AVR_ATmega103__)
217                 UBRR = (uint8_t)period;
218                 SER_UART0_485_INIT;
219         #else
220                 #error Unknown arch
221         #endif
222
223 #endif /* !CPU_I196 && !CPU_AVR */
224
225         kputs("\n\n*** DBG START ***\n");
226 }
227
228
229 /*!
230  * Output one character to the debug console
231  */
232 static void __kputchar(char c, UNUSED(void *, unused))
233 {
234         /* Poll while serial buffer is still busy */
235         KDBG_WAIT_READY();
236
237         /* Send '\n' as '\r\n' for dumb terminals */
238         if (c == '\n')
239         {
240                 KDBG_WRITE_CHAR('\r');
241                 KDBG_WAIT_READY();
242         }
243
244         KDBG_WRITE_CHAR(c);
245 }
246
247
248 void kputchar(char c)
249 {
250         /* Mask serial TX intr */
251         kdbg_irqsave_t irqsave;
252         KDBG_MASK_IRQ(irqsave);
253
254         __kputchar(c, 0);
255
256         /* Restore serial TX intr */
257         KDBG_RESTORE_IRQ(irqsave);
258 }
259
260
261 void PGM_FUNC(kprintf)(const char * PGM_ATTR fmt, ...)
262 {
263         va_list ap;
264
265         /* Mask serial TX intr */
266         kdbg_irqsave_t irqsave;
267         KDBG_MASK_IRQ(irqsave);
268
269         va_start(ap, fmt);
270         PGM_FUNC(_formatted_write)(fmt, __kputchar, 0, ap);
271         va_end(ap);
272
273         /* Restore serial TX intr */
274         KDBG_RESTORE_IRQ(irqsave);
275 }
276
277
278 void PGM_FUNC(kputs)(const char * PGM_ATTR str)
279 {
280         char c;
281
282         /* Mask serial TX intr */
283         kdbg_irqsave_t irqsave;
284         KDBG_MASK_IRQ(irqsave);
285
286         while ((c = PGM_READ_CHAR(str++)))
287                 __kputchar(c, 0);
288
289         KDBG_RESTORE_IRQ(irqsave);
290 }
291
292
293 int PGM_FUNC(__assert)(const char * PGM_ATTR cond, const char *file, int line)
294 {
295         PGM_FUNC(kputs)(file);
296         PGM_FUNC(kprintf)(PSTR(":%d: Assertion failed: "), line);
297         PGM_FUNC(kputs)(cond);
298         PGM_FUNC(kputs)(PSTR("\n"));
299         return 1;
300 }
301
302
303 int PGM_FUNC(__invalid_ptr)(void *value, const char * PGM_ATTR name, const char * PGM_ATTR file, int line)
304 {
305         PGM_FUNC(kputs)(file);
306         PGM_FUNC(kprintf)(PSTR(":%d: Invalid pointer: "), line);
307         PGM_FUNC(kputs)(name);
308         PGM_FUNC(kprintf)(PSTR(" = 0x%x\n"), value);
309         return 1;
310 }
311
312
313 void __init_wall(long *wall, int size)
314 {
315         while(size--)
316                 *wall++ = WALL_VALUE;
317 }
318
319
320 int __check_wall(long *wall, int size, const char *name, const char *file, int line)
321 {
322         int i, fail = 0;
323
324         for (i = 0; i < size; i++)
325         {
326                 if (wall[i] != WALL_VALUE)
327                 {
328                         kprintf("%s:%d: Wall broken: %s[%d] (0x%p) = 0x%lx\n",
329                                 file, line, name, i, wall + i, wall[i]);
330                         fail = 1;
331                 }
332         }
333
334         return fail;
335 }
336
337
338 /*!
339  * Dump binary data in hex
340  */
341 void kdump(const void *_buf, size_t len)
342 {
343         const unsigned char *buf = (const unsigned char *)_buf;
344
345         while (len--)
346                 kprintf("%02X", *buf++);
347         kputs("\n");
348 }
349
350 #endif /* _DEBUG */