arm: Make EL checks available in SE mode
[gem5.git] / src / base / misc.hh
index 1509ea2d2738a775b8080dfe31b23f9055fd4b71..b62548eb2ceaf43c3d05915d832e748d9f2c220c 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2014 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2002-2005 The Regents of The University of Michigan
  * All rights reserved.
  *
  *
  * Authors: Nathan Binkert
  *          Dave Greene
+ *          Andreas Sandberg
  */
 
-#ifndef __MISC_HH__
-#define __MISC_HH__
+#ifndef __BASE_MISC_HH__
+#define __BASE_MISC_HH__
 
 #include <cassert>
+#include <iostream>
 
 #include "base/compiler.hh"
 #include "base/cprintf.hh"
-#include "base/varargs.hh"
 
 #if defined(__SUNPRO_CC)
 #define __FUNCTION__ "how to fix me?"
 #endif
 
+void __exit_epilogue(int code,
+                     const char *func, const char *file, int line,
+                     const char *format) M5_ATTR_NORETURN;
+
+// General exit message, these functions will never return and will
+// either abort() if code is < 0 or exit with the code if >= 0
+template<typename ...Args> void
+__exit_message(const char *prefix, int code,
+               const char *func, const char *file, int line,
+               const char *format, const Args &...args) M5_ATTR_NORETURN;
+template<typename ...Args> void
+__exit_message(const char *prefix, int code,
+               const char *func, const char *file, int line,
+               const std::string &format, const Args &...args) M5_ATTR_NORETURN;
+
+template<typename ...Args> void
+__exit_message(const char *prefix, int code,
+               const char *func, const char *file, int line,
+               const char *format, const Args &...args)
+{
+    std::cerr << prefix << ": ";
+    ccprintf(std::cerr, format, args...);
+
+    __exit_epilogue(code, func, file, line, format);
+}
+
+template<typename ...Args> void
+__exit_message(const char *prefix, int code,
+               const char *func, const char *file, int line,
+               const std::string &format, const Args &...args)
+{
+    __exit_message(prefix, code, func, file, line, format.c_str(),
+                   args...);
+}
+
+#define exit_message(prefix, code, ...)                                 \
+    __exit_message(prefix, code, __FUNCTION__, __FILE__, __LINE__,      \
+                   __VA_ARGS__)
+
 //
 // This implements a cprintf based panic() function.  panic() should
 // be called when something happens that should never ever happen
 // calls abort which can dump core or enter the debugger.
 //
 //
-void __panic(const char *func, const char *file, int line, const char *format,
-             CPRINTF_DECLARATION) M5_ATTR_NORETURN;
-void __panic(const char *func, const char *file, int line,
-             const std::string &format, CPRINTF_DECLARATION)
-M5_ATTR_NORETURN;
-
-inline void
-__panic(const char *func, const char *file, int line,
-        const std::string &format, CPRINTF_DEFINITION)
-{
-    __panic(func, file, line, format.c_str(), VARARGS_ALLARGS);
-}
-M5_PRAGMA_NORETURN(__panic)
-#define panic(...) __panic(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__)
+#define panic(...) exit_message("panic", -1, __VA_ARGS__)
 
 //
 // This implements a cprintf based fatal() function.  fatal() should
 // be called when the simulation cannot continue due to some condition
 // that is the user's fault (bad configuration, invalid arguments,
-// etc.) and not a simulator bug.  fatal() calls exit(1), i.e., a
-// "normal" exit with an error code, as opposed to abort() like
+// etc.) and not a simulator bug.  fatal() calls  abort() like
 // panic() does.
 //
-void __fatal(const char *func, const char *file, int line, const char *format,
-             CPRINTF_DECLARATION) M5_ATTR_NORETURN;
-void __fatal(const char *func, const char *file, int line,
-             const std::string &format, CPRINTF_DECLARATION)
-    M5_ATTR_NORETURN;
-
-inline void
-__fatal(const char *func, const char *file, int line,
-        const std::string &format, CPRINTF_DEFINITION)
+#define fatal(...) exit_message("fatal", -1, __VA_ARGS__)
+
+/**
+ * Conditional panic macro that checks the supplied condition and only panics
+ * if the condition is true and allows the programmer to specify diagnostic
+ * printout.  Useful to replace if + panic, or if + print + assert, etc.
+ *
+ * @param cond Condition that is checked; if true -> panic
+ * @param ...  Printf-based format string with arguments, extends printout.
+ */
+#define panic_if(cond, ...) \
+    do { \
+        if ((cond)) \
+            exit_message("panic condition "#cond" occurred", -1, __VA_ARGS__); \
+    } while (0)
+
+
+/**
+ * Conditional fatal macro that checks the supplied condition and only causes a
+ * fatal error if the condition is true and allows the programmer to specify
+ * diagnostic printout.  Useful to replace if + fatal, or if + print + assert,
+ * etc.
+ *
+ * @param cond Condition that is checked; if true -> fatal
+ * @param ...  Printf-based format string with arguments, extends printout.
+ */
+#define fatal_if(cond, ...) \
+    do { \
+        if ((cond)) \
+            exit_message("fatal condition "#cond" occurred", 1, __VA_ARGS__); \
+    } while (0)
+
+
+void
+__base_message_epilogue(std::ostream &stream, bool verbose,
+                        const char *func, const char *file, int line,
+                        const char *format);
+
+template<typename ...Args> void
+__base_message(std::ostream &stream, const char *prefix, bool verbose,
+               const char *func, const char *file, int line,
+               const char *format, const Args &...args)
 {
-    __fatal(func, file, line, format.c_str(), VARARGS_ALLARGS);
+    stream << prefix << ": ";
+    ccprintf(stream, format, args...);
+
+    __base_message_epilogue(stream, verbose, func, file, line, format);
 }
-M5_PRAGMA_NORETURN(__fatal)
-#define fatal(...) __fatal(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__)
 
-//
-// This implements a cprintf based warn
-//
-void __warn(const char *func, const char *file, int line, const char *format,
-            CPRINTF_DECLARATION);
-inline void
-__warn(const char *func, const char *file, int line, const std::string &format,
-       CPRINTF_DECLARATION)
+template<typename ...Args> void
+__base_message(std::ostream &stream, const char *prefix, bool verbose,
+               const char *func, const char *file, int line,
+               const std::string &format, const Args &...args)
 {
-    __warn(func, file, line, format, VARARGS_ALLARGS);
+    __base_message(stream, prefix, verbose, func, file, line, format.c_str(),
+                   args...);
 }
-#define warn(...) __warn(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__)
-
-// Only print the warning message the first time it is seen.  This
-// doesn't check the warning string itself, it just only lets one
-// warning come from the statement. So, even if the arguments change
-// and that would have resulted in a different warning message,
-// subsequent messages would still be supressed.
-#define warn_once(...) do {                         \
-        static bool once = false;                   \
-        if (!once) {                                \
-            warn(__VA_ARGS__);                       \
-            once = true;                            \
-        }                                           \
+
+#define base_message(stream, prefix, verbose, ...)                      \
+    __base_message(stream, prefix, verbose, __FUNCTION__, __FILE__, __LINE__, \
+                   __VA_ARGS__)
+
+// Only print the message the first time this expression is
+// encountered.  i.e.  This doesn't check the string itself and
+// prevent duplicate strings, this prevents the statement from
+// happening more than once. So, even if the arguments change and that
+// would have resulted in a different message thoes messages would be
+// supressed.
+#define base_message_once(...) do {                     \
+        static bool once = false;                       \
+        if (!once) {                                    \
+            base_message(__VA_ARGS__);                  \
+            once = true;                                \
+        }                                               \
     } while (0)
 
-//
-// assert() that prints out the current cycle
-//
-#define m5_assert(TEST) do {                                            \
-    if (!(TEST))                                                        \
-        ccprintf(std::cerr, "Assertion failure, curTick = %d\n", curTick); \
-    assert(TEST);                                                       \
-} while (0)
+#define cond_message(cond, ...) do {            \
+        if (cond)                               \
+            base_message(__VA_ARGS__);          \
+    } while (0)
+
+#define cond_message_once(cond, ...) do {               \
+        static bool once = false;                       \
+        if (!once && cond) {                            \
+            base_message(__VA_ARGS__);                  \
+            once = true;                                \
+        }                                               \
+    } while (0)
 
-#endif // __MISC_HH__
+
+extern bool want_warn, warn_verbose;
+extern bool want_info, info_verbose;
+extern bool want_hack, hack_verbose;
+
+#define warn(...) \
+    cond_message(want_warn, std::cerr, "warn", warn_verbose, __VA_ARGS__)
+#define inform(...) \
+    cond_message(want_info, std::cout, "info", info_verbose, __VA_ARGS__)
+#define hack(...) \
+    cond_message(want_hack, std::cerr, "hack", hack_verbose, __VA_ARGS__)
+
+#define warn_once(...) \
+    cond_message_once(want_warn, std::cerr, "warn", warn_verbose, __VA_ARGS__)
+#define inform_once(...) \
+    cond_message_once(want_info, std::cout, "info", info_verbose, __VA_ARGS__)
+#define hack_once(...) \
+    cond_message_once(want_hack, std::cerr, "hack", hack_verbose, __VA_ARGS__)
+
+/**
+ * Conditional warning macro that checks the supplied condition and
+ * only prints a warning if the condition is true. Useful to replace
+ * if + warn.
+ *
+ * @param cond Condition that is checked; if true -> warn
+ * @param ...  Printf-based format string with arguments, extends printout.
+ */
+#define warn_if(cond, ...) \
+    do { \
+        if ((cond)) \
+            warn(__VA_ARGS__); \
+    } while (0)
+
+/**
+ * The chatty assert macro will function like a normal assert, but will allow the
+ * specification of additional, helpful material to aid debugging why the
+ * assertion actually failed.  Like the normal assertion, the chatty_assert
+ * will not be active in fast builds.
+ *
+ * @param cond Condition that is checked; if false -> assert
+ * @param ...  Printf-based format string with arguments, extends printout.
+ */
+#ifdef NDEBUG
+#define chatty_assert(cond, ...)
+#else //!NDEBUG
+#define chatty_assert(cond, ...)                                                \
+    do {                                                                        \
+        if (!(cond)) {                                                          \
+            base_message(std::cerr, "assert("#cond") failing", 1, __VA_ARGS__); \
+            assert(cond);                                                       \
+        }                                                                       \
+    } while (0)
+#endif // NDEBUG
+#endif // __BASE_MISC_HH__