Browse Source

Support for loading sub-32 wide data from irom.

Johny Mattsson 9 years ago
parent
commit
0c924e56c6
5 changed files with 162 additions and 0 deletions
  1. 54 0
      app/include/rom.h
  2. 97 0
      app/user/user_exceptions.c
  3. 5 0
      app/user/user_exceptions.h
  4. 4 0
      app/user/user_main.c
  5. 2 0
      include/c_types.h

+ 54 - 0
app/include/rom.h

@@ -37,3 +37,57 @@ extern unsigned char * base64_decode(const unsigned char *src, size_t len, size_
 // initialized because it uses mem_malloc
 
 extern void mem_init(void * start_addr);
+
+
+// Hardware exception handling
+struct exception_frame
+{
+  uint32_t epc;
+  uint32_t ps;
+  uint32_t sar;
+  uint32_t unused;
+  union {
+    struct {
+      uint32_t a0;
+      // note: no a1 here!
+      uint32_t a2;
+      uint32_t a3;
+      uint32_t a4;
+      uint32_t a5;
+      uint32_t a6;
+      uint32_t a7;
+      uint32_t a8;
+      uint32_t a9;
+      uint32_t a10;
+      uint32_t a11;
+      uint32_t a12;
+      uint32_t a13;
+      uint32_t a14;
+      uint32_t a15;
+    };
+    uint32_t a_reg[15];
+  };
+  uint32_t cause;
+};
+
+/**
+ * C-level exception handler callback prototype.
+ *
+ * Does not need an RFE instruction - it is called through a wrapper which
+ * performs state capture & restore, as well as the actual RFE.
+ *
+ * @param ef An exception frame containing the relevant state from the
+ *           exception triggering. This state may be manipulated and will
+ *           be applied on return.
+ * @param cause The exception cause number.
+ */
+typedef void (*exception_handler_fn) (struct exception_frame *ef, uint32_t cause);
+
+/**
+ * Sets the exception handler function for a particular exception cause.
+ * @param handler The exception handler to install.
+ *                If NULL, reverts to the XTOS default handler.
+ * @returns The previous exception handler, or NULL if none existed prior.
+ */
+exception_handler_fn _xtos_set_exception_handler (uint32_t cause, exception_handler_fn handler);
+

+ 97 - 0
app/user/user_exceptions.c

@@ -0,0 +1,97 @@
+/*
+ * Copyright 2015 Dius Computing Pty Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the
+ *   distribution.
+ * - Neither the name of the copyright holders nor the names of
+ *   its contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @author Johny Mattsson <jmattsson@dius.com.au>
+ */
+
+#include "user_exceptions.h"
+
+#define LOAD_MASK   0x00f00fu
+#define L8UI_MATCH  0x000002u
+#define L16UI_MATCH 0x001002u
+#define L16SI_MATCH 0x009002u
+
+
+void load_non_32_wide_handler (struct exception_frame *ef, uint32_t cause)
+{
+  /* If this is not EXCCAUSE_LOAD_STORE_ERROR you're doing it wrong! */
+  (void)cause;
+
+  uint32_t epc1 = ef->epc;
+  uint32_t excvaddr;
+  uint32_t insn;
+  asm (
+    "rsr   %0, EXCVADDR;"    /* read out the faulting address */
+    "movi  a4, ~3;"          /* prepare a mask for the EPC */
+    "and   a4, a4, %2;"      /* apply mask for 32bit aligned base */
+    "l32i  a5, a4, 0;"       /* load part 1 */
+    "l32i  a6, a4, 4;"       /* load part 2 */
+    "ssa8l %2;"              /* set up shift register for src op */
+    "src   %1, a6, a5;"      /* right shift to get faulting instruction */
+    :"=r"(excvaddr), "=r"(insn)
+    :"r"(epc1)
+    :"a4", "a5", "a6"
+  );
+
+  uint32_t valmask = 0;
+  uint32_t what = insn & LOAD_MASK;
+
+  if (what == L8UI_MATCH)
+    valmask = 0xffu;
+  else if (what == L16UI_MATCH || what == L16SI_MATCH)
+    valmask = 0xffffu;
+  else
+  {
+die:
+    /* Turns out we couldn't fix this, trigger a system break instead
+     * and hang if the break doesn't get handled. This is effectively
+     * what would happen if the default handler was installed. */
+    asm ("break 1, 1");
+    while (1) {}
+  }
+
+  /* Load, shift and mask down to correct size */
+  uint32_t val = (*(uint32_t *)(excvaddr & ~0x3));
+  val >>= (excvaddr & 0x3) * 8;
+  val &= valmask;
+
+  /* Sign-extend for L16SI, if applicable */
+  if (what == L16SI_MATCH && (val & 0x8000))
+    val |= 0xffff0000;
+
+  int regno = (insn & 0x0000f0u) >> 4;
+  if (regno == 1)
+    goto die;              /* we can't support loading into a1, just die */
+  else if (regno != 0)
+    --regno;               /* account for skipped a1 in exception_frame */
+
+  ef->a_reg[regno] = val;  /* carry out the load */
+  ef->epc += 3;            /* resume at following instruction */
+}

+ 5 - 0
app/user/user_exceptions.h

@@ -0,0 +1,5 @@
+#include "c_types.h"
+#include "rom.h"
+#include <xtensa/corebits.h>
+
+void load_non_32_wide_handler (struct exception_frame *ef, uint32_t cause) TEXT_SECTION_ATTR;

+ 4 - 0
app/user/user_main.c

@@ -16,6 +16,7 @@
 
 #include "flash_fs.h"
 #include "user_interface.h"
+#include "user_exceptions.h"
 
 #include "ets_sys.h"
 #include "driver/uart.h"
@@ -125,6 +126,9 @@ void nodemcu_init(void)
 *******************************************************************************/
 void user_init(void)
 {
+    _xtos_set_exception_handler (
+      EXCCAUSE_LOAD_STORE_ERROR, load_non_32_wide_handler);
+
     // NODE_DBG("SDK version:%s\n", system_get_sdk_version());
     // system_print_meminfo();
     // os_printf("Heap size::%d.\n",system_get_free_heap_size());

+ 2 - 0
include/c_types.h

@@ -84,6 +84,8 @@ typedef enum {
 #define ICACHE_FLASH_ATTR
 #endif /* ICACHE_FLASH */
 
+#define TEXT_SECTION_ATTR __attribute__((section(".text")))
+
 #ifndef __cplusplus
 typedef unsigned char   bool;
 #define BOOL            bool