Add Trax-support to esp-idf

This commit is contained in:
Jeroen Domburg 2016-10-17 12:18:17 +08:00
parent bdd67c98d6
commit 0aab006bb7
10 changed files with 289 additions and 4 deletions

View file

@ -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 of memory that can't be used for general purposes anymore. Disable this if you do not know
what this is. 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 # Memory to reverse for trace, used in linker script
config TRACEMEM_RESERVE_DRAM config TRACEMEM_RESERVE_DRAM
hex hex
default 0x8000 if MEMMAP_TRACEMEM default 0x8000 if MEMMAP_TRACEMEM && MEMMAP_TRACEMEM_TWOBANKS
default 0x4000 if MEMMAP_TRACEMEM && !MEMMAP_TRACEMEM_TWOBANKS
default 0x0 default 0x0
config MEMMAP_SPISRAM config MEMMAP_SPISRAM

View file

@ -43,6 +43,8 @@
#include "esp_ipc.h" #include "esp_ipc.h"
#include "esp_log.h" #include "esp_log.h"
#include "trax.h"
void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default"))); void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default")));
void start_cpu0_default(void) IRAM_ATTR; void start_cpu0_default(void) IRAM_ATTR;
#if !CONFIG_FREERTOS_UNICORE #if !CONFIG_FREERTOS_UNICORE
@ -131,6 +133,15 @@ void IRAM_ATTR call_start_cpu1()
void start_cpu0_default(void) 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 esp_set_cpu_freq(); // set CPU frequency configured in menuconfig
uart_div_modify(0, (APB_CLK_FREQ << 4) / 115200); uart_div_modify(0, (APB_CLK_FREQ << 4) / 115200);
ets_setup_syscalls(); ets_setup_syscalls();
@ -147,6 +158,9 @@ void start_cpu0_default(void)
#if !CONFIG_FREERTOS_UNICORE #if !CONFIG_FREERTOS_UNICORE
void start_cpu1_default(void) 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 // Wait for FreeRTOS initialization to finish on PRO CPU
while (port_xSchedulerRunning[0] == 0) { while (port_xSchedulerRunning[0] == 0) {
; ;

View file

@ -186,7 +186,11 @@ void heap_alloc_caps_init() {
#endif #endif
#if CONFIG_MEMMAP_TRACEMEM #if CONFIG_MEMMAP_TRACEMEM
#if CONFIG_MEMMAP_TRACEMEM_TWOBANKS
disable_mem_region((void*)0x3fff8000, (void*)0x40000000); //knock out trace mem region 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 #endif
#if 0 #if 0

View file

@ -3755,9 +3755,8 @@ In fact, nothing below this line has/is.
/* Gotcha (which seems to be deliberate in FreeRTOS, according to /* 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 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 ) is that calling vTaskEnterCritical followed by vTaskExitCritical will leave the interrupts DISABLED when the scheduler
scheduler will re-enable the interrupts instead. */ is not running. Re-enabling the scheduler will re-enable the interrupts instead. */
#if ( portCRITICAL_NESTING_IN_TCB == 1 ) #if ( portCRITICAL_NESTING_IN_TCB == 1 )

View file

@ -0,0 +1,5 @@
#
# Component Makefile
#
include $(IDF_PATH)/make/component_common.mk

View file

@ -0,0 +1,19 @@
#include <stdint.h>
#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)
);
}

View file

@ -0,0 +1,31 @@
#ifndef ERI_H
#define ERI_H
#include <stdint.h>
/*
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

View file

@ -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);

View file

@ -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

View file

@ -0,0 +1,64 @@
#include <stdio.h>
#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<<TRAXCTRL_SMPER_SHIFT);
if (units_until_stop == TRAX_DOWNCOUNT_INSTRUCTIONS) v|=TRAXCTRL_CNTU;
//Enable trace. This trace has no stop condition and will just keep on running.
eri_write(ERI_TRAX_TRAXCTRL, v);
return ESP_OK;
}
int trax_trigger_traceend_after_delay(int delay) {
#if !CONFIG_MEMMAP_TRACEMEM
return ESP_ERR_NO_MEM;
#endif
eri_write(ERI_TRAX_DELAYCNT, delay);
eri_write(ERI_TRAX_TRAXCTRL, eri_read(ERI_TRAX_TRAXCTRL)|TRAXCTRL_TRSTP);
return ESP_OK;
}