Browse Source

Move constants to ROM. Frees up 16k+ of RAM.

Accessing 8bit and 16bit constants from ROM rather than RAM comes with a
performance cost, as these loads go through the load/store exception
vector. Any performance critical constants can be forced back into RAM
as RAM_CONST_ATTR.

The entry point has changed from call_user_start() to user_start_trampoline()
in order for the exception handler to be installed early enough.
Johny Mattsson 9 years ago
parent
commit
b0f9788a6d
6 changed files with 52 additions and 9 deletions
  1. 1 1
      app/Makefile
  2. 15 0
      app/user/user_exceptions.c
  3. 15 3
      app/user/user_main.c
  4. 1 0
      include/c_types.h
  5. 5 4
      ld/eagle.app.v6.ld
  6. 15 1
      tools/esptool.py

+ 1 - 1
app/Makefile

@@ -99,7 +99,7 @@ LINKFLAGS_eagle.app.v6 = 			\
 	-nostdlib 				\
     -T$(LD_FILE) 				\
 	-Wl,--no-check-sections 		\
-    -u call_user_start 				\
+	-Wl,--wrap=_xtos_set_exception_handler \
 	-Wl,-static 				\
 	-Wl,--start-group 			\
 	-lc 					\

+ 15 - 0
app/user/user_exceptions.c

@@ -95,3 +95,18 @@ die:
   ef->a_reg[regno] = val;  /* carry out the load */
   ef->epc += 3;            /* resume at following instruction */
 }
+
+
+/**
+ * The SDK's user_main function installs a debugging handler regardless
+ * of whether there's a proper handler installed for EXCCAUSE_LOAD_STORE_ERROR,
+ * which of course breaks everything if we allow that to go through. As such,
+ * we use the linker to wrap that call and stop the SDK from shooting itself in
+ * its proverbial foot.
+ */
+exception_handler_fn
+__wrap__xtos_set_exception_handler (uint32_t cause, exception_handler_fn fn)
+{
+  if (cause != EXCCAUSE_LOAD_STORE_ERROR)
+    __real__xtos_set_exception_handler (cause, fn);
+}

+ 15 - 3
app/user/user_main.c

@@ -26,6 +26,21 @@
 #define TASK_QUEUE_LEN 4
 os_event_t *taskQueue;
 
+
+/* Note: the trampoline *must* be explicitly put into the .text segment, since
+ * by the time it is invoked the irom has not yet been mapped. This naturally
+ * also goes for anything the trampoline itself calls.
+ */
+void user_start_trampoline (void) TEXT_SECTION_ATTR;
+void user_start_trampoline (void)
+{
+   __real__xtos_set_exception_handler (
+     EXCCAUSE_LOAD_STORE_ERROR, load_non_32_wide_handler);
+
+  call_user_start ();
+}
+
+
 void task_lua(os_event_t *e){
     char* lua_argv[] = { (char *)"lua", (char *)"-i", NULL };
     NODE_DBG("Task task_lua started.\n");
@@ -126,9 +141,6 @@ 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());

+ 1 - 0
include/c_types.h

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

+ 5 - 4
ld/eagle.app.v6.ld

@@ -19,7 +19,7 @@ PHDRS
 
 
 /*  Default entry point:  */
-ENTRY(call_user_start)
+ENTRY(user_start_trampoline)
 PROVIDE(_memmap_vecbase_reset = 0x40000000);
 /* Various memory-map dependent cache attribute settings: */
 _memmap_cacheattr_wb_base = 0x00000110;
@@ -75,6 +75,10 @@ SECTIONS
     /* put font and progmem data into irom0 */
     *(.u8g_progmem.*)
 
+    /* Trade some performance for lots of ram. At the time of writing the
+     * available Lua heap went from 18248 to 34704. */
+    *(.rodata*)
+
     _irom0_text_end = ABSOLUTE(.);
     _flash_used_end = ABSOLUTE(.);
   } >irom0_0_seg :irom0_0_phdr
@@ -124,10 +128,7 @@ SECTIONS
   .rodata : ALIGN(4)
   {
     _rodata_start = ABSOLUTE(.);
-    *(.rodata)
-    *(.rodata.*)
     *(.gnu.linkonce.r.*)
-    *(.rodata1)
     __XT_EXCEPTION_TABLE__ = ABSOLUTE(.);
     *(.xt_except_table)
     *(.gcc_except_table)

+ 15 - 1
tools/esptool.py

@@ -360,6 +360,20 @@ class ELFFile:
         self._fetch_symbols()
         return self.symbols[sym]
 
+    def get_entry_point(self):
+        tool_readelf = "xtensa-lx106-elf-readelf"
+        if os.getenv('XTENSA_CORE')=='lx106':
+            tool_objcopy = "xt-readelf"
+        try:
+            proc = subprocess.Popen([tool_readelf, "-h", self.name], stdout=subprocess.PIPE)
+        except OSError:
+            print "Error calling "+tool_nm+", do you have Xtensa toolchain in PATH?"
+            sys.exit(1)
+        for l in proc.stdout:
+            fields = l.strip().split()
+            if fields[0] == "Entry":
+                return int(fields[3], 0);
+
     def load_section(self, section):
         tool_objcopy = "xtensa-lx106-elf-objcopy"
         if os.getenv('XTENSA_CORE')=='lx106':
@@ -586,7 +600,7 @@ if __name__ == '__main__':
             args.output = args.input + '-'
         e = ELFFile(args.input)
         image = ESPFirmwareImage()
-        image.entrypoint = e.get_symbol_addr("call_user_start")
+        image.entrypoint = e.get_entry_point()
         for section, start in ((".text", "_text_start"), (".data", "_data_start"), (".rodata", "_rodata_start")):
             data = e.load_section(section)
             image.add_segment(e.get_symbol_addr(start), data)