check.h 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. /**
  2. * @file check.h
  3. *
  4. * Furi crash and assert functions.
  5. *
  6. * The main problem with crashing is that you can't do anything without disturbing registers,
  7. * and if you disturb registers, you won't be able to see the correct register values in the debugger.
  8. *
  9. * Current solution works around it by passing the message through r12 and doing some magic with registers in crash function.
  10. * r0-r10 are stored in the ram2 on crash routine start and restored at the end.
  11. * The only register that is going to be lost is r11.
  12. *
  13. */
  14. #pragma once
  15. #ifdef __cplusplus
  16. extern "C" {
  17. #define FURI_NORETURN [[noreturn]]
  18. #else
  19. #include <stdnoreturn.h>
  20. #define FURI_NORETURN noreturn
  21. #endif
  22. // Flags instead of pointers will save ~4 bytes on furi_assert and furi_check calls.
  23. #define __FURI_ASSERT_MESSAGE_FLAG (0x01)
  24. #define __FURI_CHECK_MESSAGE_FLAG (0x02)
  25. /** Crash system */
  26. FURI_NORETURN void __furi_crash();
  27. /** Halt system */
  28. FURI_NORETURN void __furi_halt();
  29. /** Crash system with message. Show message after reboot. */
  30. #define furi_crash(message) \
  31. do { \
  32. register const void* r12 asm("r12") = (void*)message; \
  33. asm volatile("sukima%=:" : : "r"(r12)); \
  34. __furi_crash(); \
  35. } while(0)
  36. /** Halt system with message. */
  37. #define furi_halt(message) \
  38. do { \
  39. register const void* r12 asm("r12") = (void*)message; \
  40. asm volatile("sukima%=:" : : "r"(r12)); \
  41. __furi_halt(); \
  42. } while(0)
  43. /** Check condition and crash if check failed */
  44. #define furi_check(__e) \
  45. do { \
  46. if(!(__e)) { \
  47. furi_crash(__FURI_CHECK_MESSAGE_FLAG); \
  48. } \
  49. } while(0)
  50. /** Only in debug build: Assert condition and crash if assert failed */
  51. #ifdef FURI_DEBUG
  52. #define furi_assert(__e) \
  53. do { \
  54. if(!(__e)) { \
  55. furi_crash(__FURI_ASSERT_MESSAGE_FLAG); \
  56. } \
  57. } while(0)
  58. #else
  59. #define furi_assert(__e) \
  60. do { \
  61. ((void)(__e)); \
  62. } while(0)
  63. #endif
  64. #ifdef __cplusplus
  65. }
  66. #endif