Merge needed define.
[bertos.git] / drv / kdebug.c
old mode 100755 (executable)
new mode 100644 (file)
index 4e01c89..1e20615
-/*!
+/**
  * \file
  * <!--
- * Copyright 2003,2004 Develer S.r.l. (http://www.develer.com/)
- * Copyright 2000,2001,2002 Bernardo Innocenti <bernie@codewiz.org>
- * This file is part of DevLib - See devlib/README for information.
+ * This file is part of BeRTOS.
+ *
+ * Bertos is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ *
+ * Copyright 2003, 2004, 2005, 2006, 2007 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 2000, 2001, 2002 Bernardo Innocenti <bernie@codewiz.org>
+ *
  * -->
  *
- * \brief General pourpose debug functions.
+ * \brief General pourpose debug support for embedded systems (implementation).
  *
  * \version $Id$
- *
  * \author Bernardo Innocenti <bernie@develer.com>
  * \author Stefano Fedrigo <aleph@develer.com>
  */
 
-/*
- * $Log$
- * Revision 1.4  2004/06/06 18:09:51  bernie
- * Import DSP56800 changes; Print broken wall bricks in hex.
- *
- * Revision 1.3  2004/06/03 11:27:09  bernie
- * Add dual-license information.
- *
- * Revision 1.2  2004/05/23 18:21:53  bernie
- * Trim CVS logs and cleanup header info.
- *
- */
 
-#include "kdebug.h"
-#include "hw.h"
-#include "config.h"
+#include <cfg/debug.h>
+#include <cpu/irq.h>
+#include <cpu/attr.h>
+#include <cpu/types.h>
+#include <cfg/macros.h> /* for BV() */
+#include <appconfig.h>
+#warning what about these?
+//#include <hw_cpu.h>     /* for CLOCK_FREQ */
+//#include <hw_ser.h>     /* Required for bus macros overrides */
 
 #include <mware/formatwr.h> /* for _formatted_write() */
+#include <mware/pgm.h>
 
 #ifdef _DEBUG
 
-#if defined(_EMUL)
-       #include <stdio.h>
-       #define KDBG_WAIT_READY()      do {/*nop*/} while(0)
-       #define KDBG_WRITE_CHAR(c)     putchar((c))
-       #define KDBG_MASK_IRQ(old)     do {/*nop*/} while(0)
-       #define KDBG_RESTORE_IRQ()     do {/*nop*/} while(0)
-#elif defined(__I196__)
-       #include "Util196.h"
-       #define KDBG_WAIT_READY()      do {} while (!(SP_STAT & (SPSF_TX_EMPTY | SPSF_TX_INT)))
-       #define KDBG_WRITE_CHAR(c)     do { SBUF = (c); } while(0)
-       #define KDBG_MASK_IRQ(old) \
-               do { \
-                       (old) = INT_MASK1 & INT1F_TI; \
-                       INT_MASK1 &= ~INT1F_TI; \
-               } while(0)
-       #define KDBG_RESTORE_IRQ(old)  do { INT_MASK1 |= (old); }
-#elif defined(__AVR__)
-       #include <avr/io.h>
-       #if CONFIG_KDEBUG_PORT == 0
-               #ifndef __AVR_ATmega103__
-                       #define UCR UCSR0B
-                       #define UDR UDR0
-                       #define USR UCSR0A
-               #endif
-               #define KDBG_WAIT_READY()     do { loop_until_bit_is_set(USR, UDRE); } while(0)
-               #define KDBG_WRITE_CHAR(c)    do { UCR |= BV(TXEN); UDR = (c); } while(0)
-               #define KDBG_MASK_IRQ(old)    do { (old) = UCR & BV(TXCIE); cbi(UCR, TXCIE); } while(0)
-               #define KDBG_RESTORE_IRQ(old) do { UCR |= (old); } while(0)
-       #elif CONFIG_KDEBUG_PORT == 1
-               #define KDBG_WAIT_READY()     do { loop_until_bit_is_set(UCSR1A, UDRE); } while(0)
-               #define KDBG_WRITE_CHAR(c)    do { UCSR1B |= BV(TXEN); UDR1 = (c); } while(0)
-               #define KDBG_MASK_IRQ(old)    do { (old) = UCSR1B & BV(TXCIE); cbi(UCSR1B, TXCIE); } while(0)
-               #define KDBG_RESTORE_IRQ(old) do { UCSR1B |= (old); } while(0)
-       #else
-               #error CONFIG_KDEBUG_PORT should be either 0 or 1
-       #endif
-#elif defined(__MWERKS__) && (defined(__m56800E__) || defined(__m56800__))
-       /* Debugging go through the JTAG interface. The MSL library already
-          implements the console I/O correctly. */
-       #include <stdio.h>
-       #define KDBG_WAIT_READY()
-       #define KDBG_WRITE_CHAR(c)        do { char ch=c; fwrite(&ch,1,1,stdout); } while (0)
-       #define KDBG_MASK_IRQ(old)
-       #define KDBG_RESTORE_IRQ(old)
-#else
-       #error Unknown architecture
+#if CPU_HARVARD && !defined(_PROGMEM)
+       #error This module build correctly only in program memory!
 #endif
 
 
-void kdbg_init(void)
-{
-#if defined(__I196__)
-
-       /* Set serial port for 19200bps 8N1 */
-       INT_MASK1 &= ~(INT1F_TI | INT1F_RI);
-       SP_CON = SPCF_RECEIVE_ENABLE | SPCF_MODE1;
-       ioc1_img |= IOC1F_TXD_SEL | IOC1F_EXTINT_SRC;
-       IOC1 = ioc1_img;
-       BAUD_RATE = 0x33;
-       BAUD_RATE = 0x80;
-
-#elif defined(__AVR__)
-
-       /* Compute the baud rate */
-       uint16_t period = (((CLOCK_FREQ / 16UL) + (CONFIG_KDEBUG_BAUDRATE / 2)) / CONFIG_KDEBUG_BAUDRATE) - 1;
-
-       #ifdef __AVR_ATmega64__
-               #if CONFIG_KDEBUG_PORT == 0
-
-                       /* Set the baud rate */
-                       UBRR0H = (uint8_t)(period>>8);
-                       UBRR0L = (uint8_t)period;
-
-               #elif CONFIG_KDEBUG_PORT == 1
-
-                       UBRR1H = (uint8_t)(period>>8);
-                       UBRR1L = (uint8_t)period;
-
-               #else
-                       #error CONFIG_KDEBUG_PORT should be either 0 or 1
-               #endif
-       #elif defined (__AVR_ATmega103__)
+#if OS_HOSTED
+       #include <stdio.h>
+       #define KDBG_WAIT_READY()      do { /*nop*/ } while(0)
+       #define KDBG_WRITE_CHAR(c)     putc((c), stderr)
+       #define KDBG_MASK_IRQ(old)     do { (void)(old); } while(0)
+       #define KDBG_RESTORE_IRQ(old)  do { /*nop*/ } while(0)
+       typedef char kdbg_irqsave_t; /* unused */
 
-               /* Set the baud rate */
-               UBRR = (uint8_t)period;
+       #define kdbg_hw_init() do {} while (0) ///< Not needed
 
-       #else
-               #error Unknown arch
+       #if CONFIG_KDEBUG_PORT == 666
+               #error BITBANG debug console missing for this platform
        #endif
+#else
+       #include CPU_CSOURCE(kdebug)
+#endif
 
-#endif /* !__I196__ && !__AVR__ */
 
-       kputs("\n\n*** DBG START ***\n");
+void kdbg_init(void)
+{
+       /* Init debug hw */
+       kdbg_hw_init();
+       kputs("\n\n*** BeRTOS DBG START ***\n");
 }
 
 
-/*!
+/**
  * Output one character to the debug console
  */
-static void kputchar(char c, UNUSED(void *unused))
+static void __kputchar(char c, UNUSED_ARG(void *, unused))
 {
        /* Poll while serial buffer is still busy */
        KDBG_WAIT_READY();
@@ -150,54 +104,136 @@ static void kputchar(char c, UNUSED(void *unused))
 }
 
 
-void PGM_FUNC(kprintf)(const char * PGM_ATTR fmt, ...)
+void kputchar(char c)
 {
-       va_list ap;
+       /* Mask serial TX intr */
+       kdbg_irqsave_t irqsave;
+       KDBG_MASK_IRQ(irqsave);
+
+       __kputchar(c, 0);
+
+       /* Restore serial TX intr */
+       KDBG_RESTORE_IRQ(irqsave);
+}
+
 
+static void PGM_FUNC(kvprintf)(const char * PGM_ATTR fmt, va_list ap)
+{
+#if CONFIG_PRINTF
        /* Mask serial TX intr */
-       unsigned char irqsave;
+       kdbg_irqsave_t irqsave;
        KDBG_MASK_IRQ(irqsave);
 
-       va_start(ap, fmt);
-       PGM_FUNC(_formatted_write)(fmt, kputchar, 0, ap);
-       va_end(ap);
+       PGM_FUNC(_formatted_write)(fmt, __kputchar, 0, ap);
 
        /* Restore serial TX intr */
        KDBG_RESTORE_IRQ(irqsave);
+#else
+       /* A better than nothing printf() surrogate. */
+       PGM_FUNC(kputs)(fmt);
+#endif /* CONFIG_PRINTF */
 }
 
+void PGM_FUNC(kprintf)(const char * PGM_ATTR fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       PGM_FUNC(kvprintf)(fmt, ap);
+       va_end(ap);
+}
 
 void PGM_FUNC(kputs)(const char * PGM_ATTR str)
 {
        char c;
 
        /* Mask serial TX intr */
-       unsigned char irqsave;
+       kdbg_irqsave_t irqsave;
        KDBG_MASK_IRQ(irqsave);
 
        while ((c = PGM_READ_CHAR(str++)))
-               kputchar(c, 0);
+               __kputchar(c, 0);
 
        KDBG_RESTORE_IRQ(irqsave);
 }
 
 
-int PGM_FUNC(__assert)(const char * PGM_ATTR cond, const char *file, int line)
+/**
+ * Cheap function to print small integers without using printf().
+ */
+int kputnum(int num)
+{
+       int output_len = 0;
+       int divisor = 10000;
+       int digit;
+
+       do
+       {
+               digit = num / divisor;
+               num %= divisor;
+
+               if (digit || output_len || divisor == 1)
+               {
+                       kputchar(digit + '0');
+                       ++output_len;
+               }
+       }
+       while (divisor /= 10);
+
+       return output_len;
+}
+
+
+static void klocation(const char * PGM_ATTR file, int line)
 {
        PGM_FUNC(kputs)(file);
-       PGM_FUNC(kprintf)(PSTR(":%d: Assertion failed: \""), line);
+       kputchar(':');
+       kputnum(line);
+       PGM_FUNC(kputs)(PGM_STR(": "));
+}
+
+int PGM_FUNC(__assert)(const char * PGM_ATTR cond, const char * PGM_ATTR file, int line)
+{
+       klocation(file, line);
+       PGM_FUNC(kputs)(PGM_STR("Assertion failed: "));
        PGM_FUNC(kputs)(cond);
-       PGM_FUNC(kputs)(PSTR("\"\n"));
+       kputchar('\n');
+       BREAKPOINT;
        return 1;
 }
 
+/*
+ * Unfortunately, there's no way to get __func__ in
+ * program memory, so we waste quite a lot of RAM in
+ * AVR and other Harvard processors.
+ */
+void PGM_FUNC(__trace)(const char *name)
+{
+       PGM_FUNC(kprintf)(PGM_STR("%s()\n"), name);
+}
+
+void PGM_FUNC(__tracemsg)(const char *name, const char * PGM_ATTR fmt, ...)
+{
+       va_list ap;
+
+       PGM_FUNC(kprintf)(PGM_STR("%s(): "), name);
+       va_start(ap, fmt);
+       PGM_FUNC(kvprintf)(fmt, ap);
+       va_end(ap);
+       kputchar('\n');
+}
 
 int PGM_FUNC(__invalid_ptr)(void *value, const char * PGM_ATTR name, const char * PGM_ATTR file, int line)
 {
-       PGM_FUNC(kputs)(file);
-       PGM_FUNC(kprintf)(PSTR(":%d: Invalid pointer: "), line);
+       klocation(file, line);
+       PGM_FUNC(kputs)(PGM_STR("Invalid ptr: "));
        PGM_FUNC(kputs)(name);
-       PGM_FUNC(kprintf)(PSTR(" = 0x%x\n"), value);
+       #if CONFIG_PRINTF
+               PGM_FUNC(kprintf)(PGM_STR(" = 0x%p\n"), value);
+       #else
+               (void)value;
+               kputchar('\n');
+       #endif
        return 1;
 }
 
@@ -209,7 +245,7 @@ void __init_wall(long *wall, int size)
 }
 
 
-int __check_wall(long *wall, int size, const char *name, const char *file, int line)
+int PGM_FUNC(__check_wall)(long *wall, int size, const char * PGM_ATTR name, const char * PGM_ATTR file, int line)
 {
        int i, fail = 0;
 
@@ -217,8 +253,14 @@ int __check_wall(long *wall, int size, const char *name, const char *file, int l
        {
                if (wall[i] != WALL_VALUE)
                {
-                       kprintf("%s:%d: Wall broken: %s[%d] (0x%p) = 0x%lx\n",
-                               file, line, name, i, wall + i, wall[i]);
+                       klocation(file, line);
+                       PGM_FUNC(kputs)(PGM_STR("Wall broken: "));
+                       PGM_FUNC(kputs)(name);
+                       #if CONFIG_PRINTF
+                               PGM_FUNC(kprintf)(PGM_STR("[%d] (0x%p) = 0x%lx\n"), i, wall + i, wall[i]);
+                       #else
+                               kputchar('\n');
+                       #endif
                        fail = 1;
                }
        }
@@ -227,7 +269,9 @@ int __check_wall(long *wall, int size, const char *name, const char *file, int l
 }
 
 
-/*!
+#if CONFIG_PRINTF
+
+/**
  * Dump binary data in hex
  */
 void kdump(const void *_buf, size_t len)
@@ -236,7 +280,9 @@ void kdump(const void *_buf, size_t len)
 
        while (len--)
                kprintf("%02X", *buf++);
-       kputs("\n");
+       kputchar('\n');
 }
 
+#endif /* CONFIG_PRINTF */
+
 #endif /* _DEBUG */