/**
 * @file debug.h
 * @brief Header file for debug.c
 * 
 * Debugging macros
 * 
 * debugging info
 * NDEBUG - no debugging
 * DEBUG - automatically set up when NDEBUG not defined
 * 
 */

#ifndef _DEBUG_H_
#define _DEBUG_H_

/**
 * @name Define for debugging prints 
 * 
 * @{
 */
//#define SCHEDULER_DEBUG
//#define THREAD_DEBUG
//#define QUEUE_DEBUG
//#define EXCEPTION_DEBUG
//#define MUTEX_DEBUG
//#define SEM_DEBUG
//#define TIMER_DEBUG
/** }@ */

#define NDEBUG

#ifndef NDEBUG
	#define DEBUG
#endif /*NDEBUG*/
	
/** Turns on the trace mode of the simulator. */
#define ___trace_on()				\
	__asm__ __volatile__ (			\
	"	.insn			\n"	\
	"	.word	0x39		\n"	\
	)


/** Turns off the trace mode of the simulator. */
#define ___trace_off()				\
	__asm__ __volatile__ (			\
	"	.insn			\n"	\
	"	.word	0x3d		\n"	\
	)


/** Instructs the simulator to dump the contents of the general registers on the console. */
#define ___reg_view()				\
	__asm__ __volatile__ (			\
	"	.insn			\n"	\
	"	.word	0x37		\n"	\
	)


/** Instructs the simulator to stop execution and exit. */
#define ___halt()				\
	__asm__ __volatile__ (			\
	"	.insn			\n"	\
	"	.word	0x28		\n"	\
	)


/** Instructs the simulator to stop execution and enter interactive mode. */
#define ___stop()				\
	__asm__ __volatile__ (			\
	"	.insn			\n"	\
	"	.word	0x29		\n"	\
	)
	
/**
 * @brief assert macro
 * @param EXPR - expression to evaluate 
 * if NDEBUG not defined assert evaluates the expression, else assert omitted
 * when expression equal to zero, assert calls panic with function name, file name 
 * and line info
 */
#ifdef NDEBUG
#define ASSERT(EXPR) 
#else
#define ASSERT(EXPR)	\
			if (!(EXPR)) {	\
				panic("Assertion failed: function %s, %s:%d, expression %s\n",  __func__ , __FILE__, __LINE__, #EXPR); \
			}
#endif
	
/**
 * @brief assert macro
 * @param expr - expression to evaluate 
 * if NDEBUG not defined assert evaluates the expression, else assert omitted
 * when expression equal to zero, assert calls panic with function name, file name 
 * and line info
 */
#ifdef NDEBUG
#define assert(expr)          do {} while (0)
#else
#define assert(expr)						\
	if (! (expr)) 						\
	{       						\
		panic ("Assertion failed in %s() at %s:%d: %s\n",       \
		__FUNCTION__, __FILE__, __LINE__, #expr);       	\
	}
#endif

/**
 * @name Dprintk functions
 * 
 * if NDEBUG not defined assert prints function name and line number 
 * followed by the string ARGS and values printed by printk
 * 
 * @{
 */
#ifdef NDEBUG
	#define dprintk(ARGS) 
	#define dprintk1(ARGS, A1)
	#define dprintk2(ARGS, A1, A2)
	#define dprintk3(ARGS, A1, A2, A3)
	#define dprintk4(ARGS, A1, A2, A3, A4)
#else
	#define dprintk(ARGS)  printk("     Debug: function %s, line %d: ", __FUNCTION__, __LINE__); printk(ARGS);
	#define dprintk1(ARGS, A1)  printk("     Debug: function %s, line %d: ", __FUNCTION__, __LINE__); printk(ARGS, A1);
	#define dprintk2(ARGS, A1, A2)  printk("     Debug: function %s, line %d: ", __FUNCTION__, __LINE__); printk(ARGS, A1, A2);
	#define dprintk3(ARGS, A1, A2, A3)  printk("     Debug: function %s, line %d: ", __FUNCTION__, __LINE__); printk(ARGS, A1, A2, A3);
	#define dprintk4(ARGS, A1, A2, A3, A4)  printk("     Debug: function %s, line %d: ", __FUNCTION__, __LINE__); printk(ARGS, A1, A2, A3, A4);	
#endif
/** }@ */
 
void panic(const char* format, ...);


#endif /* _DEBUG_H_ */
