common fw: Add a 'panic' handler

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
Change-Id: Ice3f338abfe3d361da875c3233b8a052bd6aa2c2
diff --git a/firmware/ice40-riscv/common/utils.c b/firmware/ice40-riscv/common/utils.c
index 67b292f..1ac111b 100644
--- a/firmware/ice40-riscv/common/utils.c
+++ b/firmware/ice40-riscv/common/utils.c
@@ -5,9 +5,15 @@
  * SPDX-License-Identifier: LGPL-3.0-or-later
  */
 
+#include <stdarg.h>
 #include <stdint.h>
 #include <stdbool.h>
 
+#include "console.h"
+#include "led.h"
+#include "mini-printf.h"
+#include "misc.h"
+
 char *
 hexstr(void *d, int n, bool space)
 {
@@ -29,3 +35,47 @@
 
 	return buf;
 }
+
+
+void
+_panic(const char *file, int lineno, const char *fmt, ...)
+{
+	char buf[256];
+	va_list va;
+	int l;
+
+	/* Fast hard red blinking led */
+	led_state(true);
+	led_color(255, 0, 8);
+	led_breathe(false, 0, 0);
+	led_blink(true, 75, 75);
+
+	/* Prepare buffer */
+	l = mini_snprintf(buf, 255, "PANIC @ %s:%d = ", file, lineno);
+
+	va_start(va, fmt);
+	l += mini_vsnprintf(buf+l, 255-l, fmt, va);
+	va_end(va);
+
+	buf[l] = '\n';
+	buf[l+1] = '\0';
+
+	/* Print once */
+	puts(buf);
+
+	/* Loop waiting for commands */
+	while (1) {
+		int cmd = getchar_nowait();
+
+		switch (cmd) {
+		case 'b':
+			/* Reboot */
+			reboot(2);
+			break;
+		case ' ':
+			/* Print error again */
+			puts(buf);
+			break;
+		}
+	}
+}
diff --git a/firmware/ice40-riscv/common/utils.h b/firmware/ice40-riscv/common/utils.h
index fc898f8..03359ae 100644
--- a/firmware/ice40-riscv/common/utils.h
+++ b/firmware/ice40-riscv/common/utils.h
@@ -10,3 +10,6 @@
 #include <stdbool.h>
 
 char *hexstr(void *d, int n, bool space);
+
+void _panic(const char *file, int lineno, const char *fmt, ...);
+#define panic(fmt, ...) _panic(__FILE__, __LINE__, fmt, ##__VA_ARGS__)