diff --git a/boards.txt b/boards.txt index dc0b09ed7..e6b222a9e 100644 --- a/boards.txt +++ b/boards.txt @@ -73,6 +73,10 @@ generic.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) generic.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP generic.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) generic.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +generic.menu.mmu.ext128k=128K External 23LC1024 +generic.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +generic.menu.mmu.ext1024k=1M External 64 MBit PSRAM +generic.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 generic.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM generic.menu.non32xfer.fast.build.non32xferflags= generic.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -554,6 +558,10 @@ esp8285.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) esp8285.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP esp8285.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) esp8285.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +esp8285.menu.mmu.ext128k=128K External 23LC1024 +esp8285.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +esp8285.menu.mmu.ext1024k=1M External 64 MBit PSRAM +esp8285.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 esp8285.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM esp8285.menu.non32xfer.fast.build.non32xferflags= esp8285.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -905,6 +913,10 @@ gen4iod.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) gen4iod.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP gen4iod.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) gen4iod.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +gen4iod.menu.mmu.ext128k=128K External 23LC1024 +gen4iod.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +gen4iod.menu.mmu.ext1024k=1M External 64 MBit PSRAM +gen4iod.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 gen4iod.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM gen4iod.menu.non32xfer.fast.build.non32xferflags= gen4iod.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -1171,6 +1183,10 @@ huzzah.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) huzzah.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP huzzah.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) huzzah.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +huzzah.menu.mmu.ext128k=128K External 23LC1024 +huzzah.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +huzzah.menu.mmu.ext1024k=1M External 64 MBit PSRAM +huzzah.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 huzzah.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM huzzah.menu.non32xfer.fast.build.non32xferflags= huzzah.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -1370,6 +1386,10 @@ wifi_slot.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) wifi_slot.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP wifi_slot.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) wifi_slot.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +wifi_slot.menu.mmu.ext128k=128K External 23LC1024 +wifi_slot.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +wifi_slot.menu.mmu.ext1024k=1M External 64 MBit PSRAM +wifi_slot.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 wifi_slot.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM wifi_slot.menu.non32xfer.fast.build.non32xferflags= wifi_slot.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -1695,6 +1715,10 @@ arduino-esp8266.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) arduino-esp8266.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP arduino-esp8266.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) arduino-esp8266.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +arduino-esp8266.menu.mmu.ext128k=128K External 23LC1024 +arduino-esp8266.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +arduino-esp8266.menu.mmu.ext1024k=1M External 64 MBit PSRAM +arduino-esp8266.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 arduino-esp8266.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM arduino-esp8266.menu.non32xfer.fast.build.non32xferflags= arduino-esp8266.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -1895,6 +1919,10 @@ espmxdevkit.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) espmxdevkit.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP espmxdevkit.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) espmxdevkit.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +espmxdevkit.menu.mmu.ext128k=128K External 23LC1024 +espmxdevkit.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +espmxdevkit.menu.mmu.ext1024k=1M External 64 MBit PSRAM +espmxdevkit.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 espmxdevkit.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM espmxdevkit.menu.non32xfer.fast.build.non32xferflags= espmxdevkit.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -2135,6 +2163,10 @@ oak.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) oak.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP oak.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) oak.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +oak.menu.mmu.ext128k=128K External 23LC1024 +oak.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +oak.menu.mmu.ext1024k=1M External 64 MBit PSRAM +oak.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 oak.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM oak.menu.non32xfer.fast.build.non32xferflags= oak.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -2343,6 +2375,10 @@ espduino.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) espduino.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP espduino.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) espduino.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +espduino.menu.mmu.ext128k=128K External 23LC1024 +espduino.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +espduino.menu.mmu.ext1024k=1M External 64 MBit PSRAM +espduino.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 espduino.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM espduino.menu.non32xfer.fast.build.non32xferflags= espduino.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -2541,6 +2577,10 @@ espectro.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) espectro.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP espectro.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) espectro.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +espectro.menu.mmu.ext128k=128K External 23LC1024 +espectro.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +espectro.menu.mmu.ext1024k=1M External 64 MBit PSRAM +espectro.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 espectro.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM espectro.menu.non32xfer.fast.build.non32xferflags= espectro.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -2740,6 +2780,10 @@ espino.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) espino.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP espino.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) espino.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +espino.menu.mmu.ext128k=128K External 23LC1024 +espino.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +espino.menu.mmu.ext1024k=1M External 64 MBit PSRAM +espino.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 espino.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM espino.menu.non32xfer.fast.build.non32xferflags= espino.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -2942,6 +2986,10 @@ espresso_lite_v1.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) espresso_lite_v1.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP espresso_lite_v1.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) espresso_lite_v1.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +espresso_lite_v1.menu.mmu.ext128k=128K External 23LC1024 +espresso_lite_v1.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +espresso_lite_v1.menu.mmu.ext1024k=1M External 64 MBit PSRAM +espresso_lite_v1.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 espresso_lite_v1.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM espresso_lite_v1.menu.non32xfer.fast.build.non32xferflags= espresso_lite_v1.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -3144,6 +3192,10 @@ espresso_lite_v2.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) espresso_lite_v2.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP espresso_lite_v2.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) espresso_lite_v2.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +espresso_lite_v2.menu.mmu.ext128k=128K External 23LC1024 +espresso_lite_v2.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +espresso_lite_v2.menu.mmu.ext1024k=1M External 64 MBit PSRAM +espresso_lite_v2.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 espresso_lite_v2.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM espresso_lite_v2.menu.non32xfer.fast.build.non32xferflags= espresso_lite_v2.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -3356,6 +3408,10 @@ sonoff.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) sonoff.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP sonoff.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) sonoff.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +sonoff.menu.mmu.ext128k=128K External 23LC1024 +sonoff.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +sonoff.menu.mmu.ext1024k=1M External 64 MBit PSRAM +sonoff.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 sonoff.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM sonoff.menu.non32xfer.fast.build.non32xferflags= sonoff.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -3595,6 +3651,10 @@ inventone.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) inventone.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP inventone.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) inventone.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +inventone.menu.mmu.ext128k=128K External 23LC1024 +inventone.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +inventone.menu.mmu.ext1024k=1M External 64 MBit PSRAM +inventone.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 inventone.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM inventone.menu.non32xfer.fast.build.non32xferflags= inventone.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -3794,6 +3854,10 @@ d1_mini.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) d1_mini.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP d1_mini.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) d1_mini.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +d1_mini.menu.mmu.ext128k=128K External 23LC1024 +d1_mini.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +d1_mini.menu.mmu.ext1024k=1M External 64 MBit PSRAM +d1_mini.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 d1_mini.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM d1_mini.menu.non32xfer.fast.build.non32xferflags= d1_mini.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -3993,6 +4057,10 @@ d1_mini_lite.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) d1_mini_lite.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP d1_mini_lite.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) d1_mini_lite.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +d1_mini_lite.menu.mmu.ext128k=128K External 23LC1024 +d1_mini_lite.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +d1_mini_lite.menu.mmu.ext1024k=1M External 64 MBit PSRAM +d1_mini_lite.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 d1_mini_lite.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM d1_mini_lite.menu.non32xfer.fast.build.non32xferflags= d1_mini_lite.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -4232,6 +4300,10 @@ d1_mini_pro.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) d1_mini_pro.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP d1_mini_pro.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) d1_mini_pro.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +d1_mini_pro.menu.mmu.ext128k=128K External 23LC1024 +d1_mini_pro.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +d1_mini_pro.menu.mmu.ext1024k=1M External 64 MBit PSRAM +d1_mini_pro.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 d1_mini_pro.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM d1_mini_pro.menu.non32xfer.fast.build.non32xferflags= d1_mini_pro.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -4414,6 +4486,10 @@ d1.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) d1.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP d1.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) d1.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +d1.menu.mmu.ext128k=128K External 23LC1024 +d1.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +d1.menu.mmu.ext1024k=1M External 64 MBit PSRAM +d1.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 d1.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM d1.menu.non32xfer.fast.build.non32xferflags= d1.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -4613,6 +4689,10 @@ agruminolemon.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) agruminolemon.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP agruminolemon.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) agruminolemon.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +agruminolemon.menu.mmu.ext128k=128K External 23LC1024 +agruminolemon.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +agruminolemon.menu.mmu.ext1024k=1M External 64 MBit PSRAM +agruminolemon.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 agruminolemon.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM agruminolemon.menu.non32xfer.fast.build.non32xferflags= agruminolemon.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -4832,6 +4912,10 @@ nodemcu.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) nodemcu.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP nodemcu.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) nodemcu.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +nodemcu.menu.mmu.ext128k=128K External 23LC1024 +nodemcu.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +nodemcu.menu.mmu.ext1024k=1M External 64 MBit PSRAM +nodemcu.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 nodemcu.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM nodemcu.menu.non32xfer.fast.build.non32xferflags= nodemcu.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -5031,6 +5115,10 @@ nodemcuv2.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) nodemcuv2.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP nodemcuv2.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) nodemcuv2.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +nodemcuv2.menu.mmu.ext128k=128K External 23LC1024 +nodemcuv2.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +nodemcuv2.menu.mmu.ext1024k=1M External 64 MBit PSRAM +nodemcuv2.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 nodemcuv2.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM nodemcuv2.menu.non32xfer.fast.build.non32xferflags= nodemcuv2.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -5234,6 +5322,10 @@ modwifi.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) modwifi.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP modwifi.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) modwifi.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +modwifi.menu.mmu.ext128k=128K External 23LC1024 +modwifi.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +modwifi.menu.mmu.ext1024k=1M External 64 MBit PSRAM +modwifi.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 modwifi.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM modwifi.menu.non32xfer.fast.build.non32xferflags= modwifi.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -5453,6 +5545,10 @@ phoenix_v1.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) phoenix_v1.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP phoenix_v1.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) phoenix_v1.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +phoenix_v1.menu.mmu.ext128k=128K External 23LC1024 +phoenix_v1.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +phoenix_v1.menu.mmu.ext1024k=1M External 64 MBit PSRAM +phoenix_v1.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 phoenix_v1.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM phoenix_v1.menu.non32xfer.fast.build.non32xferflags= phoenix_v1.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -5655,6 +5751,10 @@ phoenix_v2.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) phoenix_v2.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP phoenix_v2.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) phoenix_v2.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +phoenix_v2.menu.mmu.ext128k=128K External 23LC1024 +phoenix_v2.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +phoenix_v2.menu.mmu.ext1024k=1M External 64 MBit PSRAM +phoenix_v2.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 phoenix_v2.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM phoenix_v2.menu.non32xfer.fast.build.non32xferflags= phoenix_v2.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -5857,6 +5957,10 @@ eduinowifi.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) eduinowifi.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP eduinowifi.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) eduinowifi.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +eduinowifi.menu.mmu.ext128k=128K External 23LC1024 +eduinowifi.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +eduinowifi.menu.mmu.ext1024k=1M External 64 MBit PSRAM +eduinowifi.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 eduinowifi.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM eduinowifi.menu.non32xfer.fast.build.non32xferflags= eduinowifi.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -6056,6 +6160,10 @@ wiolink.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) wiolink.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP wiolink.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) wiolink.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +wiolink.menu.mmu.ext128k=128K External 23LC1024 +wiolink.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +wiolink.menu.mmu.ext1024k=1M External 64 MBit PSRAM +wiolink.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 wiolink.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM wiolink.menu.non32xfer.fast.build.non32xferflags= wiolink.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -6255,6 +6363,10 @@ blynk.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) blynk.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP blynk.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) blynk.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +blynk.menu.mmu.ext128k=128K External 23LC1024 +blynk.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +blynk.menu.mmu.ext1024k=1M External 64 MBit PSRAM +blynk.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 blynk.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM blynk.menu.non32xfer.fast.build.non32xferflags= blynk.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -6454,6 +6566,10 @@ thing.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) thing.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP thing.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) thing.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +thing.menu.mmu.ext128k=128K External 23LC1024 +thing.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +thing.menu.mmu.ext1024k=1M External 64 MBit PSRAM +thing.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 thing.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM thing.menu.non32xfer.fast.build.non32xferflags= thing.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -6653,6 +6769,10 @@ thingdev.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) thingdev.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP thingdev.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) thingdev.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +thingdev.menu.mmu.ext128k=128K External 23LC1024 +thingdev.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +thingdev.menu.mmu.ext1024k=1M External 64 MBit PSRAM +thingdev.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 thingdev.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM thingdev.menu.non32xfer.fast.build.non32xferflags= thingdev.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -6852,6 +6972,10 @@ esp210.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) esp210.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP esp210.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) esp210.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +esp210.menu.mmu.ext128k=128K External 23LC1024 +esp210.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +esp210.menu.mmu.ext1024k=1M External 64 MBit PSRAM +esp210.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 esp210.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM esp210.menu.non32xfer.fast.build.non32xferflags= esp210.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -7051,6 +7175,10 @@ espinotee.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) espinotee.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP espinotee.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) espinotee.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +espinotee.menu.mmu.ext128k=128K External 23LC1024 +espinotee.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +espinotee.menu.mmu.ext1024k=1M External 64 MBit PSRAM +espinotee.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 espinotee.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM espinotee.menu.non32xfer.fast.build.non32xferflags= espinotee.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -7250,6 +7378,10 @@ wifiduino.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) wifiduino.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP wifiduino.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) wifiduino.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +wifiduino.menu.mmu.ext128k=128K External 23LC1024 +wifiduino.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +wifiduino.menu.mmu.ext1024k=1M External 64 MBit PSRAM +wifiduino.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 wifiduino.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM wifiduino.menu.non32xfer.fast.build.non32xferflags= wifiduino.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -7466,6 +7598,10 @@ wifinfo.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) wifinfo.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP wifinfo.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) wifinfo.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +wifinfo.menu.mmu.ext128k=128K External 23LC1024 +wifinfo.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +wifinfo.menu.mmu.ext1024k=1M External 64 MBit PSRAM +wifinfo.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 wifinfo.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM wifinfo.menu.non32xfer.fast.build.non32xferflags= wifinfo.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) @@ -7712,6 +7848,10 @@ cw01.menu.mmu.4816H=16KB cache + 48KB IRAM and 2nd Heap (shared) cw01.menu.mmu.4816H.build.mmuflags=-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP cw01.menu.mmu.3216=16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) cw01.menu.mmu.3216.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000 +cw01.menu.mmu.ext128k=128K External 23LC1024 +cw01.menu.mmu.ext128k.build.mmuflags=-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 +cw01.menu.mmu.ext1024k=1M External 64 MBit PSRAM +cw01.menu.mmu.ext1024k.build.mmuflags=-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000 cw01.menu.non32xfer.fast=Use pgm_read macros for IRAM/PROGMEM cw01.menu.non32xfer.fast.build.non32xferflags= cw01.menu.non32xfer.safe=Byte/Word access to IRAM/PROGMEM (very slow) diff --git a/cores/esp8266/Esp.cpp b/cores/esp8266/Esp.cpp index 4b031561a..8e608e631 100644 --- a/cores/esp8266/Esp.cpp +++ b/cores/esp8266/Esp.cpp @@ -29,7 +29,6 @@ #include "coredecls.h" #include "umm_malloc/umm_malloc.h" -// #include "core_esp8266_vm.h" #include #include "reboot_uart_dwnld.h" @@ -984,22 +983,11 @@ String EspClass::getSketchMD5() return result; } -void EspClass::enableVM() -{ -#ifdef UMM_HEAP_EXTERNAL - if (!vmEnabled) - install_vm_exception_handler(); - vmEnabled = true; -#endif -} - void EspClass::setExternalHeap() { #ifdef UMM_HEAP_EXTERNAL - if (vmEnabled) { - if (!umm_push_heap(UMM_HEAP_EXTERNAL)) { - panic(); - } + if (!umm_push_heap(UMM_HEAP_EXTERNAL)) { + panic(); } #endif } @@ -1016,10 +1004,8 @@ void EspClass::setIramHeap() void EspClass::setDramHeap() { #if defined(UMM_HEAP_EXTERNAL) && !defined(UMM_HEAP_IRAM) - if (vmEnabled) { - if (!umm_push_heap(UMM_HEAP_DRAM)) { - panic(); - } + if (!umm_push_heap(UMM_HEAP_DRAM)) { + panic(); } #elif defined(UMM_HEAP_IRAM) if (!umm_push_heap(UMM_HEAP_DRAM)) { @@ -1031,10 +1017,8 @@ void EspClass::setDramHeap() void EspClass::resetHeap() { #if defined(UMM_HEAP_EXTERNAL) && !defined(UMM_HEAP_IRAM) - if (vmEnabled) { - if (!umm_pop_heap()) { - panic(); - } + if (!umm_pop_heap()) { + panic(); } #elif defined(UMM_HEAP_IRAM) if (!umm_pop_heap()) { diff --git a/cores/esp8266/Esp.h b/cores/esp8266/Esp.h index d96ec9b28..0983280ba 100644 --- a/cores/esp8266/Esp.h +++ b/cores/esp8266/Esp.h @@ -221,13 +221,6 @@ class EspClass { #else uint32_t getCycleCount(); #endif // !defined(CORE_MOCK) - /** - * @brief Installs VM exception handler to support External memory (Experimental) - * - * @param none - * @return none - */ - void enableVM(); /** * @brief Push current Heap selection and set Heap selection to DRAM. * @@ -258,9 +251,6 @@ class EspClass { */ void resetHeap(); private: -#ifdef UMM_HEAP_EXTERNAL - bool vmEnabled = false; -#endif /** * @brief Replaces @a byteCount bytes of a 4 byte block on flash * diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index 417c3f26e..a3e140ef8 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -37,6 +37,7 @@ extern "C" { #include "flash_quirks.h" #include #include +#include "core_esp8266_vm.h" #define LOOP_TASK_PRIORITY 1 @@ -348,9 +349,14 @@ extern "C" void user_init(void) { cont_init(g_pcont); +#if defined(UMM_HEAP_EXTERNAL) + install_vm_exception_handler(); +#endif + #if defined(NON32XFER_HANDLER) || defined(MMU_IRAM_HEAP) install_non32xfer_exception_handler(); #endif + #if defined(MMU_IRAM_HEAP) umm_init_iram(); #endif diff --git a/cores/esp8266/core_esp8266_non32xfer.cpp b/cores/esp8266/core_esp8266_non32xfer.cpp index 4eb0e3a50..5047e8de5 100644 --- a/cores/esp8266/core_esp8266_non32xfer.cpp +++ b/cores/esp8266/core_esp8266_non32xfer.cpp @@ -64,51 +64,10 @@ static IRAM_ATTR void non32xfer_exception_handler(struct __exception_frame *ef, int cause) { do { - /* - In adapting the public domain version, a crash would come or go away with - the slightest unrelated changes elsewhere in the function. Observed that - register a15 was used for epc1, then clobbered by `rsr.` I now believe a - "&" on the output register would have resolved the problem. - - However, I have refactored the Extended ASM to reduce and consolidate - register usage and corrected the issue. - - The positioning of the Extended ASM block (as early as possible in the - compiled function) is in part controlled by the immediate need for - output variable `insn`. This placement aids in getting excvaddr read as - early as possible. - */ uint32_t insn, excvaddr; -#if 1 - { - uint32_t tmp; - __asm__ ( - "rsr.excvaddr %[vaddr]\n\t" /* Read faulting address as early as possible */ - "movi.n %[tmp], ~3\n\t" /* prepare a mask for the EPC */ - "and %[tmp], %[tmp], %[epc]\n\t" /* apply mask for 32-bit aligned base */ - "ssa8l %[epc]\n\t" /* set up shift register for src op */ - "l32i %[insn], %[tmp], 0\n\t" /* load part 1 */ - "l32i %[tmp], %[tmp], 4\n\t" /* load part 2 */ - "src %[insn], %[tmp], %[insn]\n\t" /* right shift to get faulting instruction */ - : [vaddr]"=&r"(excvaddr), [insn]"=&r"(insn), [tmp]"=&r"(tmp) - : [epc]"r"(ef->epc) :); - } -#else - { - __asm__ __volatile__ ("rsr.excvaddr %0;" : "=r"(excvaddr):: "memory"); - /* - "C" reference code for the ASM to document intent. - May also prove useful when issolating possible issues with Extended ASM, - optimizations, new compilers, etc. - */ - uint32_t epc = ef->epc; - uint32_t *pWord = (uint32_t *)(epc & ~3); - uint64_t big_word = ((uint64_t)pWord[1] << 32) | pWord[0]; - uint32_t pos = (epc & 3) * 8; - insn = (uint32_t)(big_word >>= pos); - } -#endif + /* Extract instruction and faulting data address */ + __EXCEPTION_HANDLER_PREAMBLE(ef, excvaddr, insn); uint32_t what = insn & LOAD_MASK; uint32_t valmask = 0; diff --git a/cores/esp8266/core_esp8266_non32xfer.h b/cores/esp8266/core_esp8266_non32xfer.h index 93151239c..83f8a06cf 100644 --- a/cores/esp8266/core_esp8266_non32xfer.h +++ b/cores/esp8266/core_esp8266_non32xfer.h @@ -7,6 +7,54 @@ extern "C" { extern void install_non32xfer_exception_handler(); + + /* + In adapting the public domain version, a crash would come or go away with + the slightest unrelated changes elsewhere in the function. Observed that + register a15 was used for epc1, then clobbered by `rsr.` I now believe a + "&" on the output register would have resolved the problem. + + However, I have refactored the Extended ASM to reduce and consolidate + register usage and corrected the issue. + + The positioning of the Extended ASM block (as early as possible in the + compiled function) is in part controlled by the immediate need for + output variable `insn`. This placement aids in getting excvaddr read as + early as possible. + */ + +#if 0 + { + __asm__ __volatile__ ("rsr.excvaddr %0;" : "=r"(excvaddr):: "memory"); + /* + "C" reference code for the ASM to document intent. + May also prove useful when issolating possible issues with Extended ASM, + optimizations, new compilers, etc. + */ + uint32_t epc = ef->epc; + uint32_t *pWord = (uint32_t *)(epc & ~3); + uint64_t big_word = ((uint64_t)pWord[1] << 32) | pWord[0]; + uint32_t pos = (epc & 3) * 8; + insn = (uint32_t)(big_word >>= pos); + } +#endif + +#define __EXCEPTION_HANDLER_PREAMBLE(ef, excvaddr, insn) \ + { \ + uint32_t tmp; \ + __asm__ ( \ + "rsr.excvaddr %[vaddr]\n\t" /* Read faulting address as early as possible */ \ + "movi.n %[tmp], ~3\n\t" /* prepare a mask for the EPC */ \ + "and %[tmp], %[tmp], %[epc]\n\t" /* apply mask for 32-bit aligned base */ \ + "ssa8l %[epc]\n\t" /* set up shift register for src op */ \ + "l32i %[insn], %[tmp], 0\n\t" /* load part 1 */ \ + "l32i %[tmp], %[tmp], 4\n\t" /* load part 2 */ \ + "src %[insn], %[tmp], %[insn]\n\t" /* right shift to get faulting instruction */ \ + : [vaddr]"=&r"(excvaddr), [insn]"=&r"(insn), [tmp]"=&r"(tmp) \ + : [epc]"r"(ef->epc) :); \ + } + + #ifdef __cplusplus } #endif diff --git a/cores/esp8266/core_esp8266_vm.cpp b/cores/esp8266/core_esp8266_vm.cpp new file mode 100644 index 000000000..b19360e87 --- /dev/null +++ b/cores/esp8266/core_esp8266_vm.cpp @@ -0,0 +1,399 @@ +/* + core_esp8266_vm - Implements logic to enable external SRAM/PSRAM to be used + as if it were on-chip memory by code. + + Copyright (c) 2020 Earle F. Philhower, III All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + + The original exception handler idea was taken from @pvvx's public domain + misaligned-flash-read exception handler, available here: + https://github.com/pvvx/esp8266web/blob/master/app/sdklib/system/app_main.c + + + Theory of Operation: + + The Xtensa core generates a hardware exception (unrelated to C++ exceptions) + when an address that's defined as invalid for load or store. The XTOS ROM + routines capture the machine state and call a standard C exception handler + routine (or the default one which resets the system). + + We hook into this exception callback and decode the EXCVADDR (the address + being accessed) and use the exception PC to read out the faulting + instruction. We decode that instruction and simulate it's behavior + (i.e. either loading or storing some data to a register/external memory) + and then return to the calling application. + + We use the hardware SPI interface to talk to an external SRAM/PSRAM, and + implement a simple cache to minimize the amount of times we actually need + to go out over the (slow) SPI bus. The SPI is set up in a DIO mode which + uses no more pins than normal SPI, but provides for ~2X faster transfers. + + NOTE: This works fine for processor accesses, but cannot be used by any + of the peripherals' DMA. For that, we'd need a real MMU. + + Hardware Configuration (make sure you have 3.3V compatible SRAMs): + * SPI interfaced byte-addressible SRAM/PSRAM: 24LC1024 or smaller + CS -> GPIO15 + SCK -> GPIO14 + MOSI -> GPIO13 + MISO -> GPIO12 + (note these are GPIO numbers, not the Arduion Dxx ones. Refer to your + ESP8266 board schematic for the mapping of GPIO to pin.) + * Higher density PSRAM (ESP-PSRAM64H/etc.) works as well, but may be too + large to effectively use with UMM. Only 256K is available vial malloc, + but addresses above 256K do work and can be used for fixed buffers. + +*/ + +#ifdef MMU_EXTERNAL_HEAP + +#include +#include +#include "esp8266_peri.h" +#include "core_esp8266_vm.h" +#include "core_esp8266_non32xfer.h" +#include "umm_malloc/umm_malloc.h" + + +extern "C" { + +#define SHORT_MASK 0x000008u +#define LOAD_MASK 0x00f00fu +#define L8UI_MATCH 0x000002u +#define L16UI_MATCH 0x001002u +#define L16SI_MATCH 0x009002u +#define L16_MASK 0x001000u +#define SIGNED_MASK 0x008000u +#define L32IN_MATCH 0x000008u +#define L32I_MATCH 0x002002u +#define L32R_MATCH 0x000001u +#define L32_MASK 0x002009u + +#define STORE_MASK 0x00f00fu +#define S8I_MATCH 0x004002u +#define S16I_MATCH 0x005002u +#define S16_MASK 0x001000u +#define S32I_MATCH 0x006002u +#define S32IN_MATCH 0x000009u +#define S32_MASK 0x002001u + +#define EXCCAUSE_LOAD_PROHIBITED 28 // Cache Attribute does not allow Load +#define EXCCAUSE_STORE_PROHIBITED 29 // Cache Attribute does not allow Store +#define EXCCAUSE_STORE_MASK 1 // Fast way of deciding if it's a ld or s that faulted + +// MINI SPI implementation inlined to have max performance and minimum code +// bloat. Can't include a library (SPI) in the core, anyway. + +// Place in a struct so hopefully compiler will generate smaller, base+offset +// based code to access it +typedef struct { + volatile uint32_t spi_cmd; // The SPI can change this behind our backs, so volatile! + uint32_t spi_addr; + uint32_t spi_ctrl; + uint32_t spi_ctrl1; // undocumented? Not shown in the reg map + uint32_t spi_rd_status; + uint32_t spi_ctrl2; + uint32_t spi_clock; + uint32_t spi_user; + uint32_t spi_user1; + uint32_t spi_user2; + uint32_t spi_wr_status; + uint32_t spi_pin; + uint32_t spi_slave; + uint32_t spi_slave1; + uint32_t spi_slave2; + uint32_t spi_slave3; + uint32_t spi_w[16]; // NOTE: You need a memory barrier before reading these after a read xaction + uint32_t spi_ext3; +} spi_regs; + +// The standard HSPI bus pins are used +constexpr uint8_t cs = 15; +constexpr uint8_t miso = 12; +constexpr uint8_t mosi = 13; +constexpr uint8_t sck = 14; + +#define DECLARE_SPI1 spi_regs *spi1 = (spi_regs*)&SPI1CMD + +typedef enum { spi_5mhz = 0x001c1001, spi_10mhz = 0x000c1001, spi_20mhz = 0x00041001, spi_30mhz = 0x00002001, spi_40mhz = 0x00001001 } spi_clocking; +typedef enum { sio = 0, dio = 1 } iotype; + +#if MMU_EXTERNAL_HEAP > 128 + constexpr uint32_t spi_clkval = spi_40mhz; + constexpr iotype hspi_mode = sio; +#else + constexpr uint32_t spi_clkval = spi_20mhz; + constexpr iotype hspi_mode = dio; +#endif + +constexpr int read_delay = (hspi_mode == dio) ? 4-1 : 0; + +constexpr int cache_ways = 4; // N-way, fully associative cache +constexpr int cache_words = 16; // Must be 16 words or smaller to fit in SPI buffer + +static struct cache_line { + int32_t addr; // Address, lower bits masked off + int dirty; // Needs writeback + struct cache_line *next; // We'll keep linked list in MRU order + union { + uint32_t w[cache_words]; + uint16_t s[cache_words * 2]; + uint8_t b[cache_words * 4]; + }; +} __vm_cache_line[cache_ways]; +static struct cache_line *__vm_cache; // Always points to MRU (hence the line being read/written) + +constexpr int addrmask = ~(sizeof(__vm_cache[0].w)-1); // Helper to mask off bits present in cache entry + + +static void spi_init(spi_regs *spi1) +{ + pinMode(sck, SPECIAL); + pinMode(miso, SPECIAL); + pinMode(mosi, SPECIAL); + pinMode(cs, SPECIAL); + spi1->spi_cmd = 0; + GPMUX &= ~(1 << 9); + spi1->spi_clock = spi_clkval; + spi1->spi_ctrl = 0 ; // MSB first + plain SPI mode + spi1->spi_ctrl1 = 0; // undocumented, clear for safety? + spi1->spi_ctrl2 = 0; // No add'l delays on signals + spi1->spi_user2 = 0; // No insn or insn_bits to set +} + +// Note: GCC optimization -O2 and -O3 tried and returned *slower* code than the default + +// The SPI hardware cannot make the "command" portion dual or quad, only the addr and data +// So using the command portion of the cycle will not work. Comcatenate the address +// and command into a single 32-bit chunk "address" which will be sent across both bits. + +inline ICACHE_RAM_ATTR void spi_writetransaction(spi_regs *spi1, int addr, int addr_bits, int dummy_bits, int data_bits, iotype dual) +{ + // Ensure no writes are still ongoing + while (spi1->spi_cmd & SPIBUSY) { /* busywait */ } + + spi1->spi_addr = addr; + spi1->spi_user = (addr_bits? SPIUADDR : 0) | (dummy_bits ? SPIUDUMMY : 0) | (data_bits ? SPIUMOSI : 0) | (dual ? SPIUFWDIO : 0); + spi1->spi_user1 = (addr_bits << 26) | (data_bits << 17) | dummy_bits; + // No need to set spi_user2, insn field never used + __asm ( "" ::: "memory" ); + spi1->spi_cmd = SPIBUSY; + // The write may continue on in the background, letting core do useful work instead of waiting, unless we're in cacheless mode + if (cache_ways == 0) { + while (spi1->spi_cmd & SPIBUSY) { /* busywait */ } + } +} + +inline ICACHE_RAM_ATTR uint32_t spi_readtransaction(spi_regs *spi1, int addr, int addr_bits, int dummy_bits, int data_bits, iotype dual) +{ + // Ensure no writes are still ongoing + while (spi1->spi_cmd & SPIBUSY) { /* busywait */ } + + spi1->spi_addr = addr; + spi1->spi_user = (addr_bits? SPIUADDR : 0) | (dummy_bits ? SPIUDUMMY : 0) | SPIUMISO | (dual ? SPIUFWDIO : 0); + spi1->spi_user1 = (addr_bits << 26) | (data_bits << 8) | dummy_bits; + // No need to set spi_user2, insn field never used + __asm ( "" ::: "memory" ); + spi1->spi_cmd = SPIBUSY; + while (spi1->spi_cmd & SPIBUSY) { /* busywait */ } + __asm ( "" ::: "memory" ); + return spi1->spi_w[0]; +} + +static inline ICACHE_RAM_ATTR void cache_flushrefill(spi_regs *spi1, int addr) +{ + addr &= addrmask; + struct cache_line *way = __vm_cache; + + if (__vm_cache->addr == addr) return; // Fast case, it already is the MRU + struct cache_line *last = way; + way = way->next; + + for (auto i = 1; i < cache_ways; i++) { + if (way->addr == addr) { + last->next = way->next; + way->next = __vm_cache; + __vm_cache = way; + return; + } else { + last = way; + way = way->next; + } + } + + // At this point we know the line is not in the cache and way points to the LRU. + + // We allow reads to go before writes since the write can happen in the background. + // We need to keep the data to be written back since it will be overwritten with read data + uint32_t wb[cache_words]; + if (last->dirty) { + memcpy(wb, last->w, sizeof(last->w)); + } + + // Update MRU info, list + last->next = __vm_cache; + __vm_cache = last; + + // Do the actual read + spi_readtransaction(spi1, (0x03 << 24) | addr, 32-1, read_delay, sizeof(last->w) * 8 - 1, hspi_mode); + memcpy(last->w, spi1->spi_w, sizeof(last->w)); + + // We fire a background writeback now, if needed + if (last->dirty) { + memcpy(spi1->spi_w, wb, sizeof(wb)); + spi_writetransaction(spi1, (0x02 << 24) | last->addr, 32-1, 0, sizeof(last->w) * 8 - 1, hspi_mode); + last->dirty = 0; + } + + // Update the addr at this point since we no longer need the old one + last->addr = addr; +} + +static inline ICACHE_RAM_ATTR void spi_ramwrite(spi_regs *spi1, int addr, int data_bits, uint32_t val) +{ + if (cache_ways == 0) { + spi1->spi_w[0] = val; + spi_writetransaction(spi1, (0x02<<24) | addr, 32-1, 0, data_bits, hspi_mode); + } else { + cache_flushrefill(spi1, addr); + __vm_cache->dirty = 1; + addr -= __vm_cache->addr; + switch (data_bits) { + case 31: __vm_cache->w[addr >> 2] = val; break; + case 7: __vm_cache->b[addr] = val; break; + default: __vm_cache->s[addr >> 1] = val; break; + } + } +} + +static inline ICACHE_RAM_ATTR uint32_t spi_ramread(spi_regs *spi1, int addr, int data_bits) +{ + if (cache_ways == 0) { + spi1->spi_w[0] = 0; + return spi_readtransaction(spi1, (0x03 << 24) | addr, 32-1, read_delay, data_bits, hspi_mode); + } else { + cache_flushrefill(spi1, addr); + addr -= __vm_cache->addr; + switch (data_bits) { + case 31: return __vm_cache->w[addr >> 2]; + case 7: return __vm_cache->b[addr]; + default: return __vm_cache->s[addr >> 1]; + } + } +} + +static void (*__old_handler)(struct __exception_frame *ef, int cause); + +static ICACHE_RAM_ATTR void loadstore_exception_handler(struct __exception_frame *ef, int cause) +{ + uint32_t excvaddr; + uint32_t insn; + + /* Extract instruction and faulting data address */ + __EXCEPTION_HANDLER_PREAMBLE(ef, excvaddr, insn); + + // Check that we're really accessing VM and not some other illegal range + if ((excvaddr >> 28) != 1) { + // Reinstall the old handler, and retry the instruction to keep us out of the stack dump + _xtos_set_exception_handler(EXCCAUSE_LOAD_PROHIBITED, __old_handler); + _xtos_set_exception_handler(EXCCAUSE_STORE_PROHIBITED, __old_handler); + return; + } + + DECLARE_SPI1; + ef->epc += (insn & SHORT_MASK) ? 2 : 3; // resume at following instruction + + int regno = (insn & 0x0000f0u) >> 4; + if (regno != 0) --regno; // account for skipped a1 in exception_frame + + if (cause & EXCCAUSE_STORE_MASK) { + uint32_t val = ef->a_reg[regno]; + uint32_t what = insn & STORE_MASK; + if (what == S8I_MATCH) { + spi_ramwrite(spi1, excvaddr & 0x1ffff, 8-1, val); + } else if (what == S16I_MATCH) { + spi_ramwrite(spi1, excvaddr & 0x1ffff, 16-1, val); + } else { + spi_ramwrite(spi1, excvaddr & 0x1ffff, 32-1, val); + } + } else { + if (insn & L32_MASK) { + ef->a_reg[regno] = spi_ramread(spi1, excvaddr & 0x1ffff, 32-1); + } else if (insn & L16_MASK) { + ef->a_reg[regno] = spi_ramread(spi1, excvaddr & 0x1ffff, 16-1); + if ((insn & SIGNED_MASK ) && (ef->a_reg[regno] & 0x8000)) + ef->a_reg[regno] |= 0xffff0000; + } else { + ef->a_reg[regno] = spi_ramread(spi1, excvaddr & 0x1ffff, 8-1); + } + } +} + +void install_vm_exception_handler() +{ + __old_handler = _xtos_set_exception_handler(EXCCAUSE_LOAD_PROHIBITED, loadstore_exception_handler); + _xtos_set_exception_handler(EXCCAUSE_STORE_PROHIBITED, loadstore_exception_handler); + + DECLARE_SPI1; + + // Manually reset chip from DIO to SIO mode (HW SPI has issues with <8 bits/clocks total output) + digitalWrite(cs, HIGH); + digitalWrite(mosi, HIGH); + digitalWrite(miso, HIGH); + digitalWrite(sck, LOW); + pinMode(cs, OUTPUT); + pinMode(miso, OUTPUT); + pinMode(mosi, OUTPUT); + pinMode(sck, OUTPUT); + digitalWrite(cs, LOW); + for (int i = 0; i < 4; i++) { + digitalWrite(sck, HIGH); + digitalWrite(sck, LOW); + } + digitalWrite(cs, HIGH); + + // Set up the SPI regs + spi_init(spi1); + + // Enable streaming read/write mode + spi1->spi_w[0] = 0x40; + spi_writetransaction(spi1, 0x01<<24, 8-1, 0, 8-1, sio); + + if (hspi_mode == dio) { + // Ramp up to DIO mode + spi_writetransaction(spi1, 0x3b<<24, 8-1, 0, 0, sio); + spi1->spi_ctrl |= SPICDIO | SPICFASTRD; + } + + // Bring cache structures to baseline + if (cache_ways > 0) { + for (auto i = 0; i < cache_ways; i++) { + __vm_cache_line[i].addr = -1; // Invalid, bits set in lower region so will never match + __vm_cache_line[i].next = &__vm_cache_line[i+1]; + } + __vm_cache = &__vm_cache_line[0]; + __vm_cache_line[cache_ways - 1].next = NULL; + } + + // Hook into memory manager + umm_init_vm( (void *)0x10000000, MMU_EXTERNAL_HEAP * 1024); +} + + +}; + +#endif diff --git a/cores/esp8266/core_esp8266_vm.h b/cores/esp8266/core_esp8266_vm.h new file mode 100644 index 000000000..94681a7ee --- /dev/null +++ b/cores/esp8266/core_esp8266_vm.h @@ -0,0 +1,11 @@ +#ifdef __cplusplus +extern "C" { +#endif + +extern void install_vm_exception_handler(); + + +#ifdef __cplusplus +}; +#endif + diff --git a/cores/esp8266/exc-sethandler.cpp b/cores/esp8266/exc-sethandler.cpp index 82f829394..1551d2446 100644 --- a/cores/esp8266/exc-sethandler.cpp +++ b/cores/esp8266/exc-sethandler.cpp @@ -40,7 +40,7 @@ * */ -#if defined(NON32XFER_HANDLER) || defined(MMU_IRAM_HEAP) || defined(NEW_EXC_C_WRAPPER) +#if defined(NON32XFER_HANDLER) || defined(MMU_IRAM_HEAP) || defined(NEW_EXC_C_WRAPPER) || defined(MMU_EXTERNAL_HEAP) /* * The original module source code came from: diff --git a/cores/esp8266/umm_malloc/umm_malloc_cfg.h b/cores/esp8266/umm_malloc/umm_malloc_cfg.h index 4c14c8eb1..796a47504 100644 --- a/cores/esp8266/umm_malloc/umm_malloc_cfg.h +++ b/cores/esp8266/umm_malloc/umm_malloc_cfg.h @@ -42,7 +42,11 @@ extern "C" { #undef UMM_HEAP_IRAM #endif -// #define UMM_HEAP_EXTERNAL +#if defined(MMU_EXTERNAL_HEAP) +#define UMM_HEAP_EXTERNAL +#else +#undef UMM_HEAP_EXTERNAL +#endif /* * Assign IDs to active Heaps and tally. DRAM is always active. diff --git a/libraries/esp8266/examples/virtualmem/virtualmem.ino b/libraries/esp8266/examples/virtualmem/virtualmem.ino new file mode 100644 index 000000000..47b9396cc --- /dev/null +++ b/libraries/esp8266/examples/virtualmem/virtualmem.ino @@ -0,0 +1,138 @@ + +uint32_t cyclesToRead1Kx32(unsigned int *x, uint32_t *res) { + uint32_t b = ESP.getCycleCount(); + uint32_t sum = 0; + for (int i = 0; i < 1024; i++) { + sum += *(x++); + } + *res = sum; + return ESP.getCycleCount() - b; +} + +uint32_t cyclesToWrite1Kx32(unsigned int *x) { + uint32_t b = ESP.getCycleCount(); + uint32_t sum = 0; + for (int i = 0; i < 1024; i++) { + sum += i; + *(x++) = sum; + } + return ESP.getCycleCount() - b; +} + + +uint32_t cyclesToRead1Kx16(unsigned short *x, uint32_t *res) { + uint32_t b = ESP.getCycleCount(); + uint32_t sum = 0; + for (int i = 0; i < 1024; i++) { + sum += *(x++); + } + *res = sum; + return ESP.getCycleCount() - b; +} + +uint32_t cyclesToWrite1Kx16(unsigned short *x) { + uint32_t b = ESP.getCycleCount(); + uint32_t sum = 0; + for (int i = 0; i < 1024; i++) { + sum += i; + *(x++) = sum; + } + return ESP.getCycleCount() - b; +} + +uint32_t cyclesToRead1Kx8(unsigned char*x, uint32_t *res) { + uint32_t b = ESP.getCycleCount(); + uint32_t sum = 0; + for (int i = 0; i < 1024; i++) { + sum += *(x++); + } + *res = sum; + return ESP.getCycleCount() - b; +} + +uint32_t cyclesToWrite1Kx8(unsigned char*x) { + uint32_t b = ESP.getCycleCount(); + uint32_t sum = 0; + for (int i = 0; i < 1024; i++) { + sum += i; + *(x++) = sum; + } + return ESP.getCycleCount() - b; +} + +void setup() { + Serial.begin(115200); + Serial.printf("\n"); + + // Enabling VM does not change malloc to use the external region. It will continue to + // use the normal RAM until we request otherwise. + uint32_t *mem = (uint32_t *)malloc(1024 * sizeof(uint32_t)); + Serial.printf("Internal buffer: Address %p, free %d\n", mem, ESP.getFreeHeap()); + + // Now request from the VM heap + ESP.setExternalHeap(); + uint32_t *vm = (uint32_t *)malloc(1024 * sizeof(uint32_t)); + Serial.printf("External buffer: Address %p, free %d\n", vm, ESP.getFreeHeap()); + // Make sure we go back to the internal heap for other allocations. Don't forget to ESP.resetHeap()! + ESP.resetHeap(); + + uint32_t res; + uint32_t t; + t = cyclesToWrite1Kx32(vm); + Serial.printf("Virtual Memory Write: %d cycles for 4K\n", t); + t = cyclesToWrite1Kx32(mem); + Serial.printf("Physical Memory Write: %d cycles for 4K\n", t); + + t = cyclesToRead1Kx32(vm, &res); + Serial.printf("Virtual Memory Read: %d cycles for 4K (sum %08x)\n", t, res); + t = cyclesToRead1Kx32(mem, &res); + Serial.printf("Physical Memory Read: %d cycles for 4K (sum %08x)\n", t, res); + + t = cyclesToWrite1Kx16((uint16_t*)vm); + Serial.printf("Virtual Memory Write: %d cycles for 2K by 16\n", t); + t = cyclesToWrite1Kx16((uint16_t*)mem); + Serial.printf("Physical Memory Write: %d cycles for 2K by 16\n", t); + + t = cyclesToRead1Kx16((uint16_t*)vm, &res); + Serial.printf("Virtual Memory Read: %d cycles for 2K by 16 (sum %08x)\n", t, res); + t = cyclesToRead1Kx16((uint16_t*)mem, &res); + Serial.printf("Physical Memory Read: %d cycles for 2K by 16 (sum %08x)\n", t, res); + + t = cyclesToWrite1Kx8((uint8_t*)vm); + Serial.printf("Virtual Memory Write: %d cycles for 1K by 8\n", t); + t = cyclesToWrite1Kx8((uint8_t*)mem); + Serial.printf("Physical Memory Write: %d cycles for 1K by 8\n", t); + + t = cyclesToRead1Kx8((uint8_t*)vm, &res); + Serial.printf("Virtual Memory Read: %d cycles for 1K by 8 (sum %08x)\n", t, res); + t = cyclesToRead1Kx8((uint8_t*)mem, &res); + Serial.printf("Physical Memory Read: %d cycles for 1K by 8 (sum %08x)\n", t, res); + + // Let's use external heap to make a big ole' String + ESP.setExternalHeap(); + String s = ""; + for (int i = 0; i < 100; i++) { + s += i; + s += ' '; + } + ESP.resetHeap(); + Serial.printf("Internal free: %d\n", ESP.getFreeHeap()); + ESP.setExternalHeap(); + Serial.printf("External free: %d\n", ESP.getFreeHeap()); + ESP.resetHeap(); + Serial.printf("String: %s\n", s.c_str()); + + // Note that free/realloc will all use the heap specified when the pointer was created. + // No need to change heaps to delete an object, only to create it. + free(vm); + free(mem); + + Serial.printf("Internal free: %d\n", ESP.getFreeHeap()); + ESP.setExternalHeap(); + Serial.printf("External free: %d\n", ESP.getFreeHeap()); + ESP.resetHeap(); +} + +void loop() { + +} diff --git a/tools/boards.txt.py b/tools/boards.txt.py index d19c795c0..41cbb7f27 100755 --- a/tools/boards.txt.py +++ b/tools/boards.txt.py @@ -1233,6 +1233,10 @@ macros = { ( '.menu.mmu.4816H.build.mmuflags', '-DMMU_IRAM_SIZE=0xC000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_IRAM_HEAP' ), ( '.menu.mmu.3216', '16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared)' ), ( '.menu.mmu.3216.build.mmuflags', '-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x4000 -DMMU_SEC_HEAP=0x40108000 -DMMU_SEC_HEAP_SIZE=0x4000' ), + ( '.menu.mmu.ext128k', '128K External 23LC1024' ), + ( '.menu.mmu.ext128k.build.mmuflags', '-DMMU_EXTERNAL_HEAP=128 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000' ), + ( '.menu.mmu.ext1024k', '1M External 64 MBit PSRAM' ), + ( '.menu.mmu.ext1024k.build.mmuflags', '-DMMU_EXTERNAL_HEAP=256 -DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000' ), ]), ######################## Non 32-bit load/store exception handler