From 0aab006bb799242bad310cd9745678fd099577ff Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Mon, 17 Oct 2016 12:18:17 +0800 Subject: [PATCH] Add Trax-support to esp-idf --- components/esp32/Kconfig | 14 +++- components/esp32/cpu_start.c | 14 ++++ components/esp32/heap_alloc_caps.c | 4 + components/freertos/tasks.c | 5 +- components/xtensa-debug-module/component.mk | 5 ++ components/xtensa-debug-module/eri.c | 19 +++++ components/xtensa-debug-module/include/eri.h | 31 ++++++++ components/xtensa-debug-module/include/trax.h | 62 +++++++++++++++ .../include/xtensa-debug-module.h | 75 +++++++++++++++++++ components/xtensa-debug-module/trax.c | 64 ++++++++++++++++ 10 files changed, 289 insertions(+), 4 deletions(-) create mode 100755 components/xtensa-debug-module/component.mk create mode 100644 components/xtensa-debug-module/eri.c create mode 100644 components/xtensa-debug-module/include/eri.h create mode 100644 components/xtensa-debug-module/include/trax.h create mode 100644 components/xtensa-debug-module/include/xtensa-debug-module.h create mode 100644 components/xtensa-debug-module/trax.c diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 535df23eb..4aacd937a 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 7b2ccdc60..5c7a411c8 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -43,6 +43,8 @@ #include "esp_ipc.h" #include "esp_log.h" +#include "trax.h" + void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default"))); void start_cpu0_default(void) IRAM_ATTR; #if !CONFIG_FREERTOS_UNICORE @@ -131,6 +133,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(); @@ -147,6 +158,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 46b1125cc..04e2dc8c8 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/freertos/tasks.c b/components/freertos/tasks.c index 3cde3bf13..95e7811dd 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -3755,9 +3755,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/xtensa-debug-module/component.mk b/components/xtensa-debug-module/component.mk new file mode 100755 index 000000000..a57ae0b12 --- /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 000000000..e2c7e41eb --- /dev/null +++ b/components/xtensa-debug-module/eri.c @@ -0,0 +1,19 @@ +#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 000000000..33e4dd091 --- /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 000000000..c1b3608eb --- /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 000000000..61b218253 --- /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 000000000..18c260a97 --- /dev/null +++ b/components/xtensa-debug-module/trax.c @@ -0,0 +1,64 @@ +#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 = "log"; + +int trax_enable(trax_ena_select_t which) { +#if !CONFIG_MEMMAP_TRACEMEM + 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 + 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<