diff --git a/components/bootloader/Makefile.projbuild b/components/bootloader/Makefile.projbuild index 91be3a6d6e..50c95f9fec 100644 --- a/components/bootloader/Makefile.projbuild +++ b/components/bootloader/Makefile.projbuild @@ -8,7 +8,7 @@ # basically runs Make in the src/ directory but it needs to zero some variables # the ESP-IDF project.mk makefile exports first, to not let them interfere. # -ifeq ("$(IS_BOOTLOADER_BUILD)","") +ifndef IS_BOOTLOADER_BUILD BOOTLOADER_COMPONENT_PATH := $(COMPONENT_PATH) BOOTLOADER_BUILD_DIR=$(abspath $(BUILD_DIR_BASE)/bootloader) diff --git a/components/bootloader/src/Makefile b/components/bootloader/src/Makefile index f30e314a5f..add9c15d61 100644 --- a/components/bootloader/src/Makefile +++ b/components/bootloader/src/Makefile @@ -4,12 +4,13 @@ # PROJECT_NAME := bootloader -COMPONENTS := esptool_py bootloader log +COMPONENTS := esptool_py bootloader log spi_flash # The bootloader pseudo-component is also included in this build, for its Kconfig.projbuild to be included. # # IS_BOOTLOADER_BUILD tells the component Makefile.projbuild to be a no-op IS_BOOTLOADER_BUILD := 1 +export IS_BOOTLOADER_BUILD #We cannot include the esp32 component directly but we need its includes. #This is fixed by adding CFLAGS from Makefile.projbuild diff --git a/components/bootloader/src/main/bootloader_config.h b/components/bootloader/src/main/bootloader_config.h index 709ff41b16..f99a1c94e5 100644 --- a/components/bootloader/src/main/bootloader_config.h +++ b/components/bootloader/src/main/bootloader_config.h @@ -51,7 +51,7 @@ enum { SPI_SPEED_20M, SPI_SPEED_80M = 0xF }; -/*suppport flash size in esp32 */ +/*supported flash sizes*/ enum { SPI_SIZE_1MB = 0, SPI_SIZE_2MB, diff --git a/components/bootloader/src/main/bootloader_start.c b/components/bootloader/src/main/bootloader_start.c index a61ea77d59..e87f579f42 100644 --- a/components/bootloader/src/main/bootloader_start.c +++ b/components/bootloader/src/main/bootloader_start.c @@ -58,6 +58,7 @@ void IRAM_ATTR set_cache_and_start_app(uint32_t drom_addr, uint32_t irom_load_addr, uint32_t irom_size, uint32_t entry_addr); +static void update_flash_config(struct flash_hdr* pfhdr); void IRAM_ATTR call_start_cpu0() @@ -258,7 +259,7 @@ void bootloader_main() memset(&bs, 0, sizeof(bs)); ESP_LOGI(TAG, "compile time " __TIME__ ); - /* close watch dog here */ + /* disable watch dog here */ REG_CLR_BIT( RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN ); REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN ); SPIUnlock(); @@ -269,6 +270,8 @@ void bootloader_main() print_flash_info(&fhdr); + update_flash_config(&fhdr); + if (!load_partition_table(&bs, PARTITION_ADD)) { ESP_LOGE(TAG, "load partition table error!"); return; @@ -364,7 +367,7 @@ void unpack_load_app(const partition_pos_t* partition) uint32_t irom_size = 0; /* Reload the RTC memory sections whenever a non-deepsleep reset - is occuring */ + is occurring */ bool load_rtc_memory = rtc_get_reset_reason(0) != DEEPSLEEP_RESET; ESP_LOGD(TAG, "bin_header: %u %u %u %u %08x", image_header.magic, @@ -482,6 +485,36 @@ void IRAM_ATTR set_cache_and_start_app( (*entry)(); } +static void update_flash_config(struct flash_hdr* pfhdr) +{ + uint32_t size; + switch(pfhdr->spi_size) { + case SPI_SIZE_1MB: + size = 1; + break; + case SPI_SIZE_2MB: + size = 2; + break; + case SPI_SIZE_4MB: + size = 4; + break; + case SPI_SIZE_8MB: + size = 8; + break; + case SPI_SIZE_16MB: + size = 16; + break; + default: + size = 2; + } + Cache_Read_Disable( 0 ); + // Set flash chip size + SPIParamCfg(g_rom_flashchip.deviceId, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff); + // TODO: set mode + // TODO: set frequency + Cache_Flush(0); + Cache_Read_Enable( 0 ); +} void print_flash_info(struct flash_hdr* pfhdr) { diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 6fb47ebd07..7fc5090f4e 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -63,10 +63,22 @@ config MEMMAP_TRACEMEM of memory that can't be used for general purposes anymore. Disable this if you do not know what this is. +config MEMMAP_TRACEMEM_TWOBANKS + bool "Reserve memory for tracing both pro as well as app cpu execution" + default "n" + depends on MEMMAP_TRACEMEM && MEMMAP_SMP + help + The ESP32 contains a feature which allows you to trace the execution path the processor + has taken through the program. This is stored in a chunk of 32K (16K for single-processor) + of memory that can't be used for general purposes anymore. Disable this if you do not know + what this is. + + # Memory to reverse for trace, used in linker script config TRACEMEM_RESERVE_DRAM hex - default 0x8000 if MEMMAP_TRACEMEM + default 0x8000 if MEMMAP_TRACEMEM && MEMMAP_TRACEMEM_TWOBANKS + default 0x4000 if MEMMAP_TRACEMEM && !MEMMAP_TRACEMEM_TWOBANKS default 0x0 config MEMMAP_SPISRAM diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 51f6cebb2b..aecea66ef9 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -46,6 +46,7 @@ #include "esp_brownout.h" #include "esp_int_wdt.h" #include "esp_task_wdt.h" +#include "trax.h" void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default"))); void start_cpu0_default(void) IRAM_ATTR; @@ -135,6 +136,15 @@ void IRAM_ATTR call_start_cpu1() void start_cpu0_default(void) { +//Enable trace memory and immediately start trace. +#if CONFIG_MEMMAP_TRACEMEM +#if CONFIG_MEMMAP_TRACEMEM_TWOBANKS + trax_enable(TRAX_ENA_PRO_APP); +#else + trax_enable(TRAX_ENA_PRO); +#endif + trax_start_trace(TRAX_DOWNCOUNT_WORDS); +#endif esp_set_cpu_freq(); // set CPU frequency configured in menuconfig uart_div_modify(0, (APB_CLK_FREQ << 4) / 115200); ets_setup_syscalls(); @@ -161,6 +171,9 @@ void start_cpu0_default(void) #if !CONFIG_FREERTOS_UNICORE void start_cpu1_default(void) { +#if CONFIG_MEMMAP_TRACEMEM_TWOBANKS + trax_start_trace(TRAX_DOWNCOUNT_WORDS); +#endif // Wait for FreeRTOS initialization to finish on PRO CPU while (port_xSchedulerRunning[0] == 0) { ; diff --git a/components/esp32/heap_alloc_caps.c b/components/esp32/heap_alloc_caps.c index 46b1125ccb..04e2dc8c83 100644 --- a/components/esp32/heap_alloc_caps.c +++ b/components/esp32/heap_alloc_caps.c @@ -186,7 +186,11 @@ void heap_alloc_caps_init() { #endif #if CONFIG_MEMMAP_TRACEMEM +#if CONFIG_MEMMAP_TRACEMEM_TWOBANKS disable_mem_region((void*)0x3fff8000, (void*)0x40000000); //knock out trace mem region +#else + disable_mem_region((void*)0x3fff8000, (void*)0x3fffc000); //knock out trace mem region +#endif #endif #if 0 diff --git a/components/esp32/include/rom/spi_flash.h b/components/esp32/include/rom/spi_flash.h index ba8eebc2ce..1f14c6617a 100644 --- a/components/esp32/include/rom/spi_flash.h +++ b/components/esp32/include/rom/spi_flash.h @@ -218,7 +218,7 @@ void SelectSpiFunction(uint32_t ishspi); void spi_flash_attach(uint32_t ishspi, bool legacy); /** - * @brief SPI Read Flash status register. We use CMD 0x05. + * @brief SPI Read Flash status register. We use CMD 0x05 (RDSR). * Please do not call this function in SDK. * * @param SpiFlashChip *spi : The information for Flash, which is exported from ld file. @@ -232,7 +232,7 @@ void spi_flash_attach(uint32_t ishspi, bool legacy); SpiFlashOpResult SPI_read_status(SpiFlashChip *spi, uint32_t *status); /** - * @brief SPI Read Flash status register high 16 bit. We use CMD 0x35. + * @brief SPI Read Flash status register bits 8-15. We use CMD 0x35 (RDSR2). * Please do not call this function in SDK. * * @param SpiFlashChip *spi : The information for Flash, which is exported from ld file. @@ -243,7 +243,7 @@ SpiFlashOpResult SPI_read_status(SpiFlashChip *spi, uint32_t *status); * SPI_FLASH_RESULT_ERR : read error. * SPI_FLASH_RESULT_TIMEOUT : read timeout. */ -SpiFlashOpResult SPI_read_status_high(SpiFlashChip *spi, uint32_t *status); +SpiFlashOpResult SPI_read_status_high(uint32_t *status); /** * @brief Write status to Falsh status register. @@ -503,6 +503,12 @@ void SPI_Write_Encrypt_Disable(void); */ SpiFlashOpResult SPI_Encrypt_Write(uint32_t flash_addr, uint32_t *data, uint32_t len); + +/** @brief Global SpiFlashChip structure used by ROM functions + * + */ +extern SpiFlashChip g_rom_flashchip; + /** * @} */ diff --git a/components/esp32/ld/esp32.rom.ld b/components/esp32/ld/esp32.rom.ld index cc14d3258a..5266a679be 100644 --- a/components/esp32/ld/esp32.rom.ld +++ b/components/esp32/ld/esp32.rom.ld @@ -286,6 +286,7 @@ PROVIDE ( _global_impure_ptr = 0x3ffae0b0 ); PROVIDE ( gmtime = 0x40059848 ); PROVIDE ( gmtime_r = 0x40059868 ); PROVIDE ( g_phyFuns_instance = 0x3ffae0c4 ); +PROVIDE ( g_rom_flashchip = 0x3ffae270 ); PROVIDE ( gpio_init = 0x40009c20 ); PROVIDE ( gpio_input_get = 0x40009b88 ); PROVIDE ( gpio_input_get_high = 0x40009b9c ); @@ -1584,6 +1585,8 @@ PROVIDE ( SPIEraseBlock = 0x40062c4c ); PROVIDE ( SPIEraseChip = 0x40062c14 ); PROVIDE ( SPIEraseSector = 0x40062ccc ); PROVIDE ( spi_flash_attach = 0x40062a6c ); +/* NB: SPIUnlock @ 0x400628b0 has been replaced with an updated + version in the "spi_flash" component */ PROVIDE ( SPILock = 0x400628f0 ); PROVIDE ( SPIMasterReadModeCnfig = 0x40062b64 ); PROVIDE ( spi_modes = 0x3ff99270 ); @@ -1595,9 +1598,8 @@ PROVIDE ( SPIReadModeCnfig = 0x40062944 ); PROVIDE ( SPI_read_status = 0x4006226c ); /* This is static function, but can be used, not generated by script*/ PROVIDE ( SPI_read_status_high = 0x40062448 ); -PROVIDE ( SPIUnlock = 0x400628b0 ); PROVIDE ( SPI_user_command_read = 0x400621b0 ); -PROVIDE ( spi_w25q16 = 0x3ffae270 ); +PROVIDE ( SPI_flashchip_data = 0x3ffae270 ); PROVIDE ( SPIWrite = 0x40062d50 ); /* This is static function, but can be used, not generated by script*/ PROVIDE ( SPI_write_enable = 0x40062320 ); diff --git a/components/esptool_py/Kconfig.projbuild b/components/esptool_py/Kconfig.projbuild index 3da802296a..8bab51225e 100644 --- a/components/esptool_py/Kconfig.projbuild +++ b/components/esptool_py/Kconfig.projbuild @@ -94,4 +94,31 @@ config ESPTOOLPY_FLASHFREQ default "26m" if ESPTOOLPY_FLASHFREQ_26M default "20m" if ESPTOOLPY_FLASHFREQ_20M + +choice ESPTOOLPY_FLASHSIZE + prompt "Flash size" + default ESPTOOLPY_FLASHSIZE_2MB + help + SPI flash size, in megabytes + +config ESPTOOLPY_FLASHSIZE_1MB + bool "1 MB" +config ESPTOOLPY_FLASHSIZE_2MB + bool "2 MB" +config ESPTOOLPY_FLASHSIZE_4MB + bool "4 MB" +config ESPTOOLPY_FLASHSIZE_8MB + bool "8 MB" +config ESPTOOLPY_FLASHSIZE_16MB + bool "16 MB" +endchoice + +config ESPTOOLPY_FLASHSIZE + string + default "1MB" if ESPTOOLPY_FLASHSIZE_1MB + default "2MB" if ESPTOOLPY_FLASHSIZE_2MB + default "4MB" if ESPTOOLPY_FLASHSIZE_4MB + default "8MB" if ESPTOOLPY_FLASHSIZE_8MB + default "16MB" if ESPTOOLPY_FLASHSIZE_16MB + endmenu diff --git a/components/esptool_py/Makefile.projbuild b/components/esptool_py/Makefile.projbuild index 4d0dd1b3e5..69c01e1e7f 100644 --- a/components/esptool_py/Makefile.projbuild +++ b/components/esptool_py/Makefile.projbuild @@ -4,6 +4,7 @@ ESPPORT ?= $(CONFIG_ESPTOOLPY_PORT) ESPBAUD ?= $(CONFIG_ESPTOOLPY_BAUD) ESPFLASHMODE ?= $(CONFIG_ESPTOOLPY_FLASHMODE) ESPFLASHFREQ ?= $(CONFIG_ESPTOOLPY_FLASHFREQ) +ESPFLASHSIZE ?= $(CONFIG_ESPTOOLPY_FLASHSIZE) PYTHON ?= $(call dequote,$(CONFIG_PYTHON)) @@ -15,13 +16,15 @@ ESPTOOLPY_SRC := $(COMPONENT_PATH)/esptool/esptool.py ESPTOOLPY := $(PYTHON) $(ESPTOOLPY_SRC) --chip esp32 ESPTOOLPY_SERIAL := $(ESPTOOLPY) --port $(ESPPORT) --baud $(ESPBAUD) +ESPTOOL_FLASH_OPTIONS := --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) --flash_size $(ESPFLASHSIZE) + # the no-stub argument is temporary until esptool.py fully supports compressed uploads -ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) +ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) $(ESPTOOL_FLASH_OPTIONS) ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_APP_OFFSET) $(APP_BIN) $(APP_BIN): $(APP_ELF) $(ESPTOOLPY_SRC) - $(Q) $(ESPTOOLPY) elf2image --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) -o $@ $< + $(Q) $(ESPTOOLPY) elf2image $(ESPTOOL_FLASH_OPTIONS) -o $@ $< flash: all_binaries $(ESPTOOLPY_SRC) @echo "Flashing binaries to serial port $(ESPPORT) (app at offset $(CONFIG_APP_OFFSET))..." diff --git a/components/esptool_py/esptool b/components/esptool_py/esptool index 197ba605fe..5c6962e894 160000 --- a/components/esptool_py/esptool +++ b/components/esptool_py/esptool @@ -1 +1 @@ -Subproject commit 197ba605fe0c05e16bf4c5ec07b726adc8d86abc +Subproject commit 5c6962e894e0a118c9a4b5760876433493449260 diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index c3a279bde9..d0ab472c18 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -3784,9 +3784,8 @@ In fact, nothing below this line has/is. /* Gotcha (which seems to be deliberate in FreeRTOS, according to http://www.freertos.org/FreeRTOS_Support_Forum_Archive/December_2012/freertos_PIC32_Bug_-_vTaskEnterCritical_6400806.html -) is that calling vTaskEnterCritical followed by vTaskExitCritical will leave the interrupts DISABLED! Re-enabling the -scheduler will re-enable the interrupts instead. */ - +) is that calling vTaskEnterCritical followed by vTaskExitCritical will leave the interrupts DISABLED when the scheduler +is not running. Re-enabling the scheduler will re-enable the interrupts instead. */ #if ( portCRITICAL_NESTING_IN_TCB == 1 ) diff --git a/components/spi_flash/component.mk b/components/spi_flash/component.mk index ef497a7ecb..459da06419 100755 --- a/components/spi_flash/component.mk +++ b/components/spi_flash/component.mk @@ -1,3 +1,8 @@ COMPONENT_ADD_INCLUDEDIRS := include +ifdef IS_BOOTLOADER_BUILD +# Bootloader needs updated SPIUnlock from this file +COMPONENT_OBJS := spi_flash_rom_patch.o +endif + include $(IDF_PATH)/make/component_common.mk diff --git a/components/spi_flash/spi_flash_rom_patch.c b/components/spi_flash/spi_flash_rom_patch.c new file mode 100644 index 0000000000..7e23beaea2 --- /dev/null +++ b/components/spi_flash/spi_flash_rom_patch.c @@ -0,0 +1,72 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "rom/spi_flash.h" +#include "soc/spi_reg.h" + +static const uint32_t STATUS_QIE_BIT = (1 << 9); /* Quad Enable */ + +#define SPI_IDX 1 +#define OTH_IDX 0 + +extern SpiFlashChip SPI_flashchip_data; + +static void IRAM_ATTR Wait_SPI_Idle(void) +{ + /* Wait for SPI state machine to be idle */ + while((REG_READ(SPI_EXT2_REG(SPI_IDX)) & SPI_ST)) { + } + while(REG_READ(SPI_EXT2_REG(OTH_IDX)) & SPI_ST) { + } +} + +/* Modified version of SPIUnlock() that replaces version in ROM. + + This works around a bug where SPIUnlock sometimes reads the wrong + high status byte (RDSR2 result) and then copies it back to the + flash status, which can cause the CMP bit or Status Register + Protect bit to become set. + + Like other ROM SPI functions, this function is not designed to be + called directly from an RTOS environment without taking precautions + about interrupts, CPU coordination, flash mapping. However some of + the functions in esp_spi_flash.c call it. + */ +SpiFlashOpResult IRAM_ATTR SPIUnlock(void) +{ + uint32_t status; + + Wait_SPI_Idle(); + + if (SPI_read_status_high(&status) != SPI_FLASH_RESULT_OK) { + return SPI_FLASH_RESULT_ERR; + } + + /* Clear all bits except QIE, if it is set. + (This is different from ROM SPIUnlock, which keeps all bits as-is.) + */ + status &= STATUS_QIE_BIT; + + Wait_SPI_Idle(); + REG_WRITE(SPI_CMD_REG(SPI_IDX), SPI_FLASH_WREN); + while(REG_READ(SPI_CMD_REG(SPI_IDX)) != 0) { + } + Wait_SPI_Idle(); + + SET_PERI_REG_MASK(SPI_CTRL_REG(SPI_IDX), SPI_WRSR_2B); + if (SPI_write_status(&SPI_flashchip_data, status) != SPI_FLASH_RESULT_OK) { + return SPI_FLASH_RESULT_ERR; + } + + return SPI_FLASH_RESULT_OK; +} diff --git a/components/xtensa-debug-module/component.mk b/components/xtensa-debug-module/component.mk new file mode 100755 index 0000000000..a57ae0b12b --- /dev/null +++ b/components/xtensa-debug-module/component.mk @@ -0,0 +1,5 @@ +# +# Component Makefile +# + +include $(IDF_PATH)/make/component_common.mk diff --git a/components/xtensa-debug-module/eri.c b/components/xtensa-debug-module/eri.c new file mode 100644 index 0000000000..fc96b531fe --- /dev/null +++ b/components/xtensa-debug-module/eri.c @@ -0,0 +1,32 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include +#include "eri.h" + +uint32_t eri_read(int addr) { + uint32_t ret; + asm( + "RER %0,%1" + :"=r"(ret):"r"(addr) + ); + return ret; +} + +void eri_write(int addr, uint32_t data) { + asm volatile ( + "WER %0,%1" + ::"r"(data),"r"(addr) + ); +} + diff --git a/components/xtensa-debug-module/include/eri.h b/components/xtensa-debug-module/include/eri.h new file mode 100644 index 0000000000..33e4dd0918 --- /dev/null +++ b/components/xtensa-debug-module/include/eri.h @@ -0,0 +1,31 @@ +#ifndef ERI_H +#define ERI_H + +#include + +/* + The ERI is a bus internal to each Xtensa core. It connects, amongst others, to the debug interface, where it + allows reading/writing the same registers as available over JTAG. +*/ + + +/** + * @brief Perform an ERI read + * @param addr : ERI register to read from + * + * @return Value read + */ +uint32_t eri_read(int addr); + + +/** + * @brief Perform an ERI write + * @param addr : ERI register to write to + * @param data : Value to write + * + * @return Value read + */ +void eri_write(int addr, uint32_t data); + + +#endif \ No newline at end of file diff --git a/components/xtensa-debug-module/include/trax.h b/components/xtensa-debug-module/include/trax.h new file mode 100644 index 0000000000..c1b3608eb8 --- /dev/null +++ b/components/xtensa-debug-module/include/trax.h @@ -0,0 +1,62 @@ +#include "soc/dport_reg.h" +#include "sdkconfig.h" +#include "esp_err.h" +#include "eri.h" +#include "xtensa-debug-module.h" + + +typedef enum { + TRAX_DOWNCOUNT_WORDS, + TRAX_DOWNCOUNT_INSTRUCTIONS +} trax_downcount_unit_t; + +typedef enum { + TRAX_ENA_NONE = 0, + TRAX_ENA_PRO, + TRAX_ENA_APP, + TRAX_ENA_PRO_APP, + TRAX_ENA_PRO_APP_SWAP +} trax_ena_select_t; + + +/** + * @brief Enable the trax memory blocks to be used as Trax memory. + * + * @param pro_cpu_enable : true if Trax needs to be enabled for the pro CPU + * @param app_cpu_enable : true if Trax needs to be enabled for the pro CPU + * @param swap_regions : Normally, the pro CPU writes to Trax mem block 0 while + * the app cpu writes to block 1. Setting this to true + * inverts this. + * + * @return esp_err_t. Fails with ESP_ERR_NO_MEM if Trax enable is requested for 2 CPUs + * but memmap only has room for 1, or if Trax memmap is disabled + * entirely. + */ +int trax_enable(trax_ena_select_t ena); + +/** + * @brief Start a Trax trace on the current CPU + * + * @param units_until_stop : Set the units of the delay that gets passed to + * trax_trigger_traceend_after_delay. One of TRAX_DOWNCOUNT_WORDS + * or TRAX_DOWNCOUNT_INSTRUCTIONS. + * + * @return esp_err_t. Fails with ESP_ERR_NO_MEM if Trax is disabled. + */ +int trax_start_trace(trax_downcount_unit_t units_until_stop); + + +/** + * @brief Trigger a Trax trace stop after the indicated delay. If this is called + * before and the previous delay hasn't ended yet, this will overwrite + * that delay with the new value. The delay will always start at the time + * the function is called. + * + * @param delay : The delay to stop the trace in, in the unit indicated to + * trax_start_trace. Note: the trace memory has 4K words available. + * + * @return esp_err_t + */ +int trax_trigger_traceend_after_delay(int delay); + + diff --git a/components/xtensa-debug-module/include/xtensa-debug-module.h b/components/xtensa-debug-module/include/xtensa-debug-module.h new file mode 100644 index 0000000000..61b2182531 --- /dev/null +++ b/components/xtensa-debug-module/include/xtensa-debug-module.h @@ -0,0 +1,75 @@ +#ifndef XTENSA_DEBUG_MODULE_H +#define XTENSA_DEBUG_MODULE_H + +/* +ERI registers / OCD offsets and field definitions +*/ + +#define ERI_DEBUG_OFFSET 0x100000 + +#define ERI_TRAX_OFFSET (ERI_DEBUG_OFFSET+0) +#define ERI_PERFMON_OFFSET (ERI_DEBUG_OFFSET+0x1000) +#define ERI_OCDREG_OFFSET (ERI_DEBUG_OFFSET+0x2000) +#define ERI_MISCDBG_OFFSET (ERI_DEBUG_OFFSET+0x3000) +#define ERI_CORESIGHT_OFFSET (ERI_DEBUG_OFFSET+0x3F00) + +#define ERI_TRAX_TRAXID (ERI_TRAX_OFFSET+0x00) +#define ERI_TRAX_TRAXCTRL (ERI_TRAX_OFFSET+0x04) +#define ERI_TRAX_TRAXSTAT (ERI_TRAX_OFFSET+0x08) +#define ERI_TRAX_TRAXDATA (ERI_TRAX_OFFSET+0x0C) +#define ERI_TRAX_TRAXADDR (ERI_TRAX_OFFSET+0x10) +#define ERI_TRAX_TRIGGERPC (ERI_TRAX_OFFSET+0x14) +#define ERI_TRAX_PCMATCHCTRL (ERI_TRAX_OFFSET+0x18) +#define ERI_TRAX_DELAYCNT (ERI_TRAX_OFFSET+0x1C) +#define ERI_TRAX_MEMADDRSTART (ERI_TRAX_OFFSET+0x20) +#define ERI_TRAX_MEMADDREND (ERI_TRAX_OFFSET+0x24) + +#define TRAXCTRL_TREN (1<<0) //Trace enable. Tracing starts on 0->1 +#define TRAXCTRL_TRSTP (1<<1) //Trace Stop. Make 1 to stop trace. +#define TRAXCTRL_PCMEN (1<<2) //PC match enable +#define TRAXCTRL_PTIEN (1<<4) //Processor-trigger enable +#define TRAXCTRL_CTIEN (1<<5) //Cross-trigger enable +#define TRAXCTRL_TMEN (1<<7) //Tracemem Enable. Always set. +#define TRAXCTRL_CNTU (1<<9) //Post-stop-trigger countdown units; selects when DelayCount-- happens. + //0 - every 32-bit word written to tracemem, 1 - every cpu instruction +#define TRAXCTRL_TSEN (1<<11) //Undocumented/deprecated? +#define TRAXCTRL_SMPER_SHIFT 12 //Send sync every 2^(9-smper) messages. 7=reserved, 0=no sync msg +#define TRAXCTRL_SMPER_MASK 0x7 //Synchronization message period +#define TRAXCTRL_PTOWT (1<<16) //Processor Trigger Out (OCD halt) enabled when stop triggered +#define TRAXCTRL_PTOWS (1<<17) //Processor Trigger Out (OCD halt) enabled when trace stop completes +#define TRAXCTRL_CTOWT (1<<20) //Cross-trigger Out enabled when stop triggered +#define TRAXCTRL_CTOWS (1<<21) //Cross-trigger Out enabled when trace stop completes +#define TRAXCTRL_ITCTO (1<<22) //Integration mode: cross-trigger output +#define TRAXCTRL_ITCTIA (1<<23) //Integration mode: cross-trigger ack +#define TRAXCTRL_ITATV (1<<24) //replaces ATID when in integration mode: ATVALID output +#define TRAXCTRL_ATID_MASK 0x7F //ARB source ID +#define TRAXCTRL_ATID_SHIFT 24 +#define TRAXCTRL_ATEN (1<<31) //ATB interface enable + +#define TRAXSTAT_TRACT (1<<0) //Trace active flag. +#define TRAXSTAT_TRIG (1<<1) //Trace stop trigger. Clears on TREN 1->0 +#define TRAXSTAT_PCMTG (1<<2) //Stop trigger caused by PC match. Clears on TREN 1->0 +#define TRAXSTAT_PJTR (1<<3) //JTAG transaction result. 1=err in preceding jtag transaction. +#define TRAXSTAT_PTITG (1<<4) //Stop trigger caused by Processor Trigger Input. Clears on TREN 1->0 +#define TRAXSTAT_CTITG (1<<5) //Stop trigger caused by Cross-Trigger Input. Clears on TREN 1->0 +#define TRAXSTAT_MEMSZ_SHIFT 8 //Traceram size inducator. Usable trace ram is 2^MEMSZ bytes. +#define TRAXSTAT_MEMSZ_MASK 0x1F +#define TRAXSTAT_PTO (1<<16) //Processor Trigger Output: current value +#define TRAXSTAT_CTO (1<<17) //Cross-Trigger Output: current value +#define TRAXSTAT_ITCTOA (1<<22) //Cross-Trigger Out Ack: current value +#define TRAXSTAT_ITCTI (1<<23) //Cross-Trigger Input: current value +#define TRAXSTAT_ITATR (1<<24) //ATREADY Input: current value + +#define TRAXADDR_TADDR_SHIFT 0 //Trax memory address, in 32-bit words. +#define TRAXADDR_TADDR_MASK 0x1FFFFF //Actually is only as big as the trace buffer size max addr. +#define TRAXADDR_TWRAP_SHIFT 21 //Amount of times TADDR has overflown +#define TRAXADDR_TWRAP_MASK 0x3FF +#define TRAXADDR_TWSAT (1<<31) //1 if TWRAP has overflown, clear by disabling tren. + +#define PCMATCHCTRL_PCML_SHIFT 0 //Amount of lower bits to ignore in pc trigger register +#define PCMATCHCTRL_PCML_MASK 0x1F +#define PCMATCHCTRL_PCMS (1<<31) //PC Match Sense, 0 - match when procs PC is in-range, 1 - match when + //out-of-range + + +#endif \ No newline at end of file diff --git a/components/xtensa-debug-module/trax.c b/components/xtensa-debug-module/trax.c new file mode 100644 index 0000000000..5174e44776 --- /dev/null +++ b/components/xtensa-debug-module/trax.c @@ -0,0 +1,84 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include "soc/dport_reg.h" +#include "sdkconfig.h" +#include "esp_err.h" +#include "eri.h" +#include "xtensa-debug-module.h" +#include "trax.h" +#include "esp_log.h" + +#define TRACEMEM_MUX_PROBLK0_APPBLK1 0 +#define TRACEMEM_MUX_BLK0_ONLY 1 +#define TRACEMEM_MUX_BLK1_ONLY 2 +#define TRACEMEM_MUX_PROBLK1_APPBLK0 3 + +static const char* TAG = "trax"; + +int trax_enable(trax_ena_select_t which) +{ +#if !CONFIG_MEMMAP_TRACEMEM + ESP_LOGE(TAG, "Trax_enable called, but trax is disabled in menuconfig!"); + return ESP_ERR_NO_MEM; +#endif +#if !CONFIG_MEMMAP_TRACEMEM_TWOBANKS + if (which == TRAX_ENA_PRO_APP || which == TRAX_ENA_PRO_APP_SWAP) return ESP_ERR_NO_MEM; +#endif + if (which == TRAX_ENA_PRO_APP || which == TRAX_ENA_PRO_APP_SWAP) { + WRITE_PERI_REG(DPORT_TRACEMEM_MUX_MODE_REG, (which == TRAX_ENA_PRO_APP_SWAP)?TRACEMEM_MUX_PROBLK1_APPBLK0:TRACEMEM_MUX_PROBLK0_APPBLK1); + } else { + WRITE_PERI_REG(DPORT_TRACEMEM_MUX_MODE_REG, TRACEMEM_MUX_BLK0_ONLY); + } + WRITE_PERI_REG(DPORT_PRO_TRACEMEM_ENA_REG, (which == TRAX_ENA_PRO_APP || which == TRAX_ENA_PRO_APP_SWAP || which == TRAX_ENA_PRO)); + WRITE_PERI_REG(DPORT_APP_TRACEMEM_ENA_REG, (which == TRAX_ENA_PRO_APP || which == TRAX_ENA_PRO_APP_SWAP || which == TRAX_ENA_APP)); + return ESP_OK; +} + + +int trax_start_trace(trax_downcount_unit_t units_until_stop) +{ +#if !CONFIG_MEMMAP_TRACEMEM + ESP_LOGE(TAG, "Trax_start_trace called, but trax is disabled in menuconfig!"); + return ESP_ERR_NO_MEM; +#endif + uint32_t v; + if (eri_read(ERI_TRAX_TRAXSTAT)&TRAXSTAT_TRACT) { + ESP_LOGI(TAG, "Stopping active trace first."); + //Trace is active. Stop trace. + eri_write(ERI_TRAX_DELAYCNT, 0); + eri_write(ERI_TRAX_TRAXCTRL, eri_read(ERI_TRAX_TRAXCTRL)|TRAXCTRL_TRSTP); + //ToDo: This will probably trigger a trace done interrupt. ToDo: Fix, but how? -JD + eri_write(ERI_TRAX_TRAXCTRL, 0); + } + eri_write(ERI_TRAX_PCMATCHCTRL, 31); //do not stop at any pc match + v=TRAXCTRL_TREN | TRAXCTRL_TMEN | TRAXCTRL_PTOWS | (1<