From 822533fd922f2c67169599b472605c87569c1f2d Mon Sep 17 00:00:00 2001
From: Angus Gratton <gus@projectgus.com>
Date: Mon, 8 Jun 2015 18:00:44 +1000
Subject: [PATCH] Interrupt support refactor

Write inline versions for SDK-based interrupt convenience functions.
---
 FreeRTOS/Source/portable/esp8266/port.c      | 40 ++++++++++-----
 FreeRTOS/Source/portable/esp8266/portmacro.h | 14 +-----
 core/include/esp/cpu.h                       | 26 ++++++++++
 core/include/esp8266.h                       |  1 +
 include/xtensa_interrupts.h                  | 53 ++++++++++++++++++++
 5 files changed, 109 insertions(+), 25 deletions(-)
 create mode 100644 core/include/esp/cpu.h
 create mode 100644 include/xtensa_interrupts.h

diff --git a/FreeRTOS/Source/portable/esp8266/port.c b/FreeRTOS/Source/portable/esp8266/port.c
index d40340e..ae2b579 100644
--- a/FreeRTOS/Source/portable/esp8266/port.c
+++ b/FreeRTOS/Source/portable/esp8266/port.c
@@ -131,7 +131,7 @@ void IRAM PendSV(enum SVC_ReqType req)
 	else if(req == SVC_MACLayer)
 		pending_maclayer_sv= 1;
 
-	xthal_set_intset(1<<ETS_SOFT_INUM);
+	xthal_set_intset(BIT(INUM_SOFT));
 	vPortExitCritical();
 }
 
@@ -162,7 +162,6 @@ void xPortSysTickHandle (void)
 	{
 		if(xTaskIncrementTick() !=pdFALSE )
 		{
-			//GPIO_REG_WRITE(GPIO_STATUS_W1TS_ADDRESS, 0x40);
 			vTaskSwitchContext();
 		}
 	}
@@ -174,8 +173,8 @@ void xPortSysTickHandle (void)
  */
 portBASE_TYPE xPortStartScheduler( void )
 {
-    _xt_isr_attach(ETS_SOFT_INUM, SV_ISR);
-    sdk__xt_isr_unmask(1<<ETS_SOFT_INUM);
+    _xt_isr_attach(INUM_SOFT, SV_ISR);
+    _xt_isr_unmask(BIT(INUM_SOFT));
 
     /* Initialize system tick timer interrupt and schedule the first tick. */
     sdk__xt_tick_timer_init();
@@ -236,25 +235,42 @@ void _xt_isr_attach(uint8_t i, _xt_isr func)
     isr[i] = func;
 }
 
-uint16_t _xt_isr_handler(uint16_t i)
+uint16_t IRAM _xt_isr_handler(uint16_t i)
 {
     uint8_t index;
 
-    if (i & (1 << ETS_WDT_INUM)) {
-	index = ETS_WDT_INUM;
+    /* I think this is implementing some kind of interrupt priority or
+       short-circuiting an expensive ffs for most common interrupts - ie
+       WDT And GPIO are common or high priority, then remaining flags.
+    */
+    if (i & (1 << INUM_WDT)) {
+	index = INUM_WDT;
     }
-    else if (i & (1 << ETS_GPIO_INUM)) {
-	index = ETS_GPIO_INUM;
+    else if (i & (1 << INUM_GPIO)) {
+	index = INUM_GPIO;
     }else {
 	index = __builtin_ffs(i) - 1;
 
-	if (index == ETS_MAX_INUM) {
-	    i &= ~(1 << ETS_MAX_INUM);
+	if (index == INUM_MAX) {
+	    /* I don't understand what happens here. INUM_MAX is not
+	       the highest interrupt number listed (and the isr array
+	       has 16 entries).
+
+	       Clearing that flag and then setting index to
+	       __builtin_ffs(i)-1 may result in index == 255 if no
+	       higher flags are set, unless this is guarded against
+	       somehow by the caller?
+
+	       I also don't understand why the code is written like
+	       this in esp_iot_rtos_sdk instead of just putting the i
+	       &= line near the top... Probably no good reason?
+	    */
+	    i &= ~(1 << INUM_MAX);
 	    index = __builtin_ffs(i) - 1;
 	}
     }
 
-    sdk__xt_clear_ints(1<<index);
+    _xt_clear_ints(1<<index);
 
     isr[index]();
 
diff --git a/FreeRTOS/Source/portable/esp8266/portmacro.h b/FreeRTOS/Source/portable/esp8266/portmacro.h
index 1391275..242c253 100644
--- a/FreeRTOS/Source/portable/esp8266/portmacro.h
+++ b/FreeRTOS/Source/portable/esp8266/portmacro.h
@@ -75,6 +75,7 @@ extern "C" {
 #include <stdint.h>
 #include    <xtruntime.h>
 #include    "xtensa_rtos.h"
+#include "xtensa_interrupts.h"
 
 /*-----------------------------------------------------------
  * Port specific definitions for ESP8266
@@ -187,19 +188,6 @@ not necessary for to use this port.  They are defined so the common demo files
 /* ESPTODO: These parts of the FreeRTOS support are still in binary libraries */
 #define vApplicationStackOverflowHook sdk_vApplicationStackOverflowHook
 
-/* XTensa interrupt management functions, used in port.c.
-   Some (w/ sdk_ prefix) are implemented in blob libs */
-void        sdk__xt_int_exit (void);
-void        sdk__xt_user_exit (void);
-void        sdk__xt_tick_timer_init (void);
-void        sdk__xt_isr_unmask (uint32_t unmask);
-void        sdk__xt_isr_mask (uint32_t mask);
-uint32_t    sdk__xt_read_ints (void);
-void        sdk__xt_clear_ints(uint32_t mask);
-typedef void (* _xt_isr)(void);
-void        _xt_isr_attach (uint8_t i, _xt_isr func);
-void	    sdk__xt_timer_int1(void);
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/core/include/esp/cpu.h b/core/include/esp/cpu.h
new file mode 100644
index 0000000..0a029c8
--- /dev/null
+++ b/core/include/esp/cpu.h
@@ -0,0 +1,26 @@
+/* esp/cpu.h
+ *
+ * Details relating to the ESP8266 Xtensa core.
+ *
+ */
+#ifndef _ESP_CPU_H
+#define _ESP_CPU_H
+
+/* Interrupt numbers for level 1 exception handler.
+ *
+ * Currently the UserExceptionVector calls down to _xt_isr_handler,
+ * defined in port.c, for at least some of these interrupts. Some are handled
+ * on the SDK side, though.
+ */
+typedef enum {
+    INUM_SPI = 2,
+    INUM_GPIO = 4,
+    INUM_UART = 5,
+    INUM_MAX = 6,
+    INUM_SOFT = 7,
+    INUM_WDT = 8,
+    INUM_FRC_TIMER1 = 9,
+} xt_isr_num_t;
+
+#endif
+
diff --git a/core/include/esp8266.h b/core/include/esp8266.h
index ce7a4c7..f6ede41 100644
--- a/core/include/esp8266.h
+++ b/core/include/esp8266.h
@@ -13,6 +13,7 @@
 
 #include "common_macros.h"
 #include "esp/registers.h"
+#include "esp/cpu.h"
 #include "esp/iomux.h"
 #include "esp/gpio.h"
 
diff --git a/include/xtensa_interrupts.h b/include/xtensa_interrupts.h
new file mode 100644
index 0000000..f2c75f8
--- /dev/null
+++ b/include/xtensa_interrupts.h
@@ -0,0 +1,53 @@
+/* Xtensa interrupt management functions
+ *
+ * Some (w/ sdk_ prefix) are implemented in binary libs, rest are
+ * inlines replacing functions in the binary libraries.
+ *
+ * Part of esp-open-rtos
+ * Copyright (C) 2015 Superhouse Automation Pty Ltd
+ * BSD Licensed as described in the file LICENSE
+ */
+#ifndef _XTENSA_INTERRUPTS_H
+#define _XTENSA_INTERRUPTS_H
+#include <stdint.h>
+#include <xtensa/hal.h>
+
+void sdk__xt_int_exit (void);
+void sdk__xt_user_exit (void);
+void sdk__xt_tick_timer_init (void);
+void sdk__xt_timer_int1(void);
+
+INLINED void _xt_isr_unmask (uint32_t unmask)
+{
+    uint32_t intenable;
+    asm volatile ("rsr %0, intenable" : "=a" (intenable));
+    intenable |= unmask;
+    asm volatile ("wsr %0, intenable" :: "a" (intenable));
+}
+
+INLINED void _xt_isr_mask (uint32_t mask)
+{
+    uint32_t intenable;
+    asm volatile ("rsr %0, intenable" : "=a" (intenable));
+    intenable &= ~mask;
+    asm volatile ("wsr %0, intenable" :: "a" (intenable));
+}
+
+INLINED uint32_t _xt_read_ints (void)
+{
+    uint32_t interrupt;
+    asm volatile ("rsr %0, interrupt" : "=a" (interrupt));
+    return interrupt;
+}
+
+INLINED void _xt_clear_ints(uint32_t mask)
+{
+    asm volatile ("wsr %0, intclear" :: "a" (mask));
+}
+
+typedef void (* _xt_isr)(void);
+/* This function is implemeneted in FreeRTOS port.c at the moment,
+   should be moved or converted to an inline */
+void        _xt_isr_attach (uint8_t i, _xt_isr func);
+
+#endif