Event Recorder and Component Viewer  Version 1.5.1
MDK Debugger Views for Status and Event Information
Built-in Functions

Read CPU register value

The SCVD interpreter has the following built-in functions for calculation of stack memory usage, access to CPU registers and application program symbols.

Function Name Description
__CalcMemUsed Provide memory usage information for stack area in user application program.
__FindSymbol Get address value of a symbol in user application program.
__GetRegVal Read the value of processor register from the target processor.
__Offset_of Get offset of type member defined with the typedef.
__size_of Number of elements of an array defined by a symbol in user application.
__Symbol_exists Check if a specific symbol exists in the user application program.

 


__CalcMemUsed

Provide memory usage information for stack area in user application program.

uint32_t __CalcMemUsed (uint32_t StackAddress, uint32_t StackSize, uint32_t FillPattern, uint32_t MagicValue)
Parameters
StackAddressStart address of memory area
StackSizeSize of memory area in Bytes
FillPatternInitial value of memory area, used to identify memory usage
MagicValueInitial value at start address of memory area, used to identify memory (stack) overflow
Returns
A packed 32-bit integer value that indicates memory usage in bytes, in percent, and memory overflow:
  • Bit 0..19 Used memory in Bytes (how many bytes of FillPattern are overwritten)
  • Bit 20..28 Used memory in percent (how many percent of FillPattern are overwritten)
  • Bit 31 Memory overflow (MagicValue is overwritten)

The function provides information about the memory usage of a stack area and is typically applied to calculate the utilization of RTOS thread stacks. It assumes that the memory has been filled with a pattern value. Optionally there might be a value (called magic value) at the start of the memory that is used to detect stack overflows.

Example 1

C source file

uint32_t tstack[200/4]; // 200 bytes stack space
void StackTest (void) {
uint32_t i;
memset (tstack, 0x8A, sizeof (tstack));
tstack[0] = 0xE25A2EA5;
for (i=(200/4)-1; i >= 10; i--) {
tstack[i] = i;
}
}

*.SCVD file

<?xml version="1.0" encoding="utf-8"?>
<component_viewer schemaVersion="0.1" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="Component_Viewer.xsd">
<component name="MyExample" version="1.0.0"/> <!-- name and version of the component -->
<objects>
<object name="MyProgram">
<var name="StackStart" type="int32_t" value="0" />
<var name="StackSize" type="int32_t" value="0" />
<var name="StackUsage" type="int32_t" value="0" />
<calc>
StackStart = __FindSymbol ("tstack");
StackSize = __size_of ("tstack") * 4;
StackUsage = __CalcMemUsed (StackStart, StackSize, 0x8A8A8A8A, 0xE25A2EA5);
</calc>
<out name="MyProgram">
<item alert="(StackUsage >> 31)"
property="tstack @%x[StackStart] size=%x[StackSize]"
value="Usage %x[StackUsage &amp; 0xFFFFF] %d[(StackUsage>>20) &amp; 0xFF]%%" />
</out>
</object>
</objects>
</component_viewer>

Output

Example 2

Typical usage with an RTOS thread control block.

<component_viewer...>
<typedefs>
<!-- Task/Thread Control Block, debugger reads 52 bytes -->
<typedef name="Thread_CB" info="RTOS Task Control Block" size="52">
:
<member name="Stack" type="uint32_t" offset="44" info="Pointer to Task Stack memory block"/>
:
<!-- Helper variables for Stack-usage calculation -->
<var name="StackSize" type="uint32_t" />
<var name="StkUse" type="uint32_t" />
<var name="BytesUsed" type="uint32_t" />
<var name="Percentage" type="uint32_t" />
<var name="StkOverflow" type="int32_t" />
<var name="ShowStackInfo" type="int32_t" />
</typedef>
</typedefs>
</objects>
<object name="Threads">
<readlist name="TCB" type="*Thread_CB" symbol="os_TCB" based="1" count="10" init="1" />
<!-- Stack Usage Calculation when watermark check is enabled (ShowStackInfo) -->
<calc cond="TCB[i].ShowStackInfo && ((i != (TCB._count - 1)) && ((stackinfo >> 28) & 0x01))" >
StkUse = __CalcMemUsed (TCB[i].Stack, TCB[i].StackSize, 0xCCCCCCCC, 0xE25A2EA5);
TCB[i].StkOverflow = (StkUse & 0x80000000) ? 1 : 0;
TCB[i].StkUse &= ~0x80000000;
TCB[i].BytesUsed = (StkUse & 0xFFFFF);
TCB[i].Percentage = (StkUse >> 20) & 0xFF;
</calc>
</object>
</objects>
</component_viewer>

 


__FindSymbol

Get address value of a symbol in the user application program.

int32_t __FindSymbol (symbol_name)
Parameters
symbol_nameReference to a symbol (examples: "main", "os_active_TCB", "tasks.c/xSchedulerRunning").
Returns
address value Address of the symbol.

The function searches for a symbol and returns the address value of the symbol in the user application.

Note
If the symbol cannot be found, then an error in the Component Viewer is displayed.

C source file

uint32_t tstack[200/4]; // 200 bytes stack space
void StackTest (void) {
uint32_t i;
memset (tstack, 0x8A, sizeof (tstack));
tstack[0] = 0xE25A2EA5;
for (i=(200/4)-1; i >= 10; i--) {
tstack[i] = i;
}
}

*.SCVD file

<?xml version="1.0" encoding="utf-8"?>
<component_viewer schemaVersion="0.1" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="Component_Viewer.xsd">
<component name="MyExample" version="1.0.0"/> <!-- name and version of the component -->
<objects>
<object name="MyProgram">
<var name="StackStart" type="int32_t" value="0" />
<var name="StackSize" type="int32_t" value="0" />
<var name="StackUsage" type="int32_t" value="0" />
<calc>
StackStart = __FindSymbol ("tstack");
StackSize = __size_of ("tstack") * 4;
StackUsage = __CalcMemUsed (StackStart, StackSize, 0x8A8A8A8A, 0xE25A2EA5);
</calc>
<out name="MyProgram">
<item alert="(StackUsage >> 31)"
property="tstack @%x[StackStart] size=%x[StackSize]"
value="Usage %x[StackUsage &amp; 0xFFFFF] %d[(StackUsage>>20) &amp; 0xFF]%%" />
</out>
</object>
</objects>
</component_viewer>

Output

 


__GetRegVal

__GetRegVal | Read the value of processor register from the target processor.

uint32_t __GetRegVal (char * RegisterName)
Parameters
RegisterNamePointer to the name of a CPU register: "PSP", "MSP", ....
Returns
Value of the CPU register

The function reads the value of a CPU register.

Register Name Description
R0 - R12 General-purpose registers
R13 Stack pointer (SP)
R14 Link Register (LR)
R15 Program Counter (PC)
XPSR Combined Program Status Register
MSP Main Stack Pointer
PSP Process Stack Pointer
BASEPRI Base Priority Mask Register
PRIMASK Exception Mask Register
FAULTMASK Fault Mask Register
CONTROL Control Register

Domain specifier x is required on ARMv8-M architecture for some registers to specify Non-Secure (x=NS) or Secure (x=S) access domain. Names of these registers then become as follows:

Register Name Description
MSP_x Main Stack Pointer
PSP_x Process Stack Pointer
MSPLIM_x Main Stack Pointer Limit Register
PSPLIM_x Process Stack Pointer Limit Register
BASEPRI_x Base Priority Mask Register
PRIMASK_x Exception Mask Register
FAULTMASK_x Fault Mask Register
CONTROL_x Control Register

Example:

<objects>
<object name="CPU Registers">
<var name="R0" type="uint32_t" value="0"/>
<var name="R1" type="uint32_t" value="0"/>
<var name="R2" type="uint32_t" value="0"/>
<var name="R3" type="uint32_t" value="0"/>
<var name="XPSR" type="uint32_t" value="0"/>
<!-- ARMv8M registers -->
<var name="PSP_NS" type="uint32_t" value="0"/>
<var name="PSP_S" type="uint32_t" value="0"/>
<!-- Read registers -->
<calc>
R0 = __GetRegVal ("R0");
R1 = __GetRegVal ("R1");
R2 = __GetRegVal ("R2");
R3 = __GetRegVal ("R3");
XPSR = __GetRegVal ("XPSR");
</calc>
<calc cond="NonSecure">
PSP_NS = __GetRegVal ("PSP_NS");
</calc>
<calc cond="Secure">
PSP_S = __GetRegVal ("PSP_S");
</calc>
</object>
</objects>

__Symbol_exists

int32_t __Symbol_exists (symbol_name)

Search for symbol

Parameters
symbol_nameReference to a symbol (examples: "main", "os_active_TCB", "tasks.c/xSchedulerRunning").
Returns

  • 1 for true - symbol present in user application
  • 0 for false - symbol not found

The function searches for a debug symbol in the loaded user application.

and returns 1 when the symbol was found, otherwise 0 for false.  


__Offset_of

uint32_t __Offset_of (typedef_mem_name)

Get offset of type member

Parameters
typedef_mem_nameIs the member name of a specified type and has the form typedef_name:typedef_member_name.
Returns
The offset value of the specified typedef member.

The function returns the offset value of the specified typedef member. When using a <typedef> element with the import attribute, __Offset_of returns for members that are defined in the SCVD file but not present in the compiled image the value -1. The value -1 indicates that a member does not exist in the image.

Example:

__Offset_of (Thread_CB:Task_ID)

__size_of

int32_t __size_of (symbol_name)

Number of elements of an array defined by a symbol in user application

Parameters
symbol_nameReference to a symbol (examples: "main", "os_active_TCB", "tasks.c/xSchedulerRunning").
Returns
number of elements of an array defined in a user application

The function searches for a debug symbol in the loaded user application. If the symbol is found it returns the number of elements of an array that is addressed by this symbol. If the symbol is not found, an error message is displayed.

Example:

User application code (file MyTest.c):

struct {
unsigned char c0;
unsigned char c1;
unsigned int i;
} MyList [20];
static int MyVar[10];

The following statements in the SCVD file output the number of elements of each variable. For 'MyList' the value is 20. The value 20 for 'MyVar' is only displayed when the variable exists.

<out name="MyTest">
<item property="Elements of 'MyList'" value="%d[__size_of(&quot;MyList&quot;)]"/>
<item cond="__Symbol_exists(&quot;MyTest.c/MyVar&quot;)" property="Elements of 'MyVar'" value="%d[__size_of(&quot;MyTest.c/MyVar&quot;)]"/>
</out>