Upgrading Platform Configuration Editor-generated configuration to support a DSTREAM-ST trace capture device

If you have a platform configuration created using older versions of DS-5, you might have customized it for your requirements. If so, you can manually edit your configuration to add DSTREAM-ST support. Manually editing the configuration is recommended if you do not want to lose any of your customizations.

Note: The Platform Configuration Editor (PCE) in the newer versions of DS-5 generate configurations which support full debug and trace with the DSTREAM-ST unit. If you have not customized the configuration, then regenerating the configuration using the PCE in the newer versions of DS-5 is recommended.

This knowledge base article shows you how to modify an existing platform configuration for the Arm Versatile Express A15x2 target to add full debug and trace support for a DSTREAM-ST unit. You can then make similar changes to any configuration that already has DSTREAM support for debug and trace using this article as an example.

This article references the below files which are found in the generated platform configuration:

  • project_types.xml - XML defining the available types of debug activity.
  • dtsl_config_script.py - Jython script for DTSL configuration.

Additionally, have a look at the project_types.xml and dtsl_config_script.py DIFF files which illustrate the specific changes made in this knowledge base article.

Creating a new DTSL class to add DSTREAM-ST specific configuration

The first step is to modify the DTSL Jython script, dtsl_config_script.py, to create a new DTSL class.

The new DTSL class provides the configuration for the debugger when connecting to your DSTREAM-ST unit and extends the existing DSTREAM configuration DtslScript class to add DSTREAM-ST specific configuration.

Note: The construction of DTSL devices such as the ETM and TPIU remains the same as the DSTREAM configuration.

The below code shows the beginning of the new DTSL class which is derived from the DSTREAM DtslScript class.

The code defines a new tab page which lists the possible trace capture devices when using a DSTREAM-ST unit. The entry for the example platform is defined as ("DSTREAM", "Streaming Trace").


   class DtslScript_DSTREAM_ST(DtslScript):
    @staticmethod
    def getOptionList():
        return [
            DTSLv1.tabSet("options", "Options", childOptions=[
            DTSLv1.tabPage("traceBuffer", "Trace Buffer", childOptions=[
                DTSLv1.radioEnumOption(
                        name='traceCapture',
                        displayName = 'Trace capture method',
                        description="Specify how trace data is to be collected",
                        defaultValue="none",
                        setter=DtslScript.setTraceCaptureMethod,
                        values = [
                            ("none", "None"),
                            ("ETB", "On Chip Trace Buffer (ETB)"),
                            ("DSTREAM", "Streaming Trace")
                        ]
        ),
       ],
       DTSLv1.tabPage("cortexA15", "Cortex-A15", childOptions=[ 
           ... same as for DSTREAM...

    

Note: You must also include the other option tab pages which configure core and ITM trace, but they can be left the same as in the DSTREAM configuration.

Adding new project types entries

Before adding DSTREAM-ST functionality, you must add a new DSTREAM-ST activity to the project_types.xml file in your configuration files. You must add a new activity for each execution environment and core for which you want DSTREAM-ST debug and trace support.

For example, for the Arm Versatile Express A15x2 target used here, it means adding six new activities: A new entry for the A15_0, A15_1, and A15x2 SMP cores in each of the BARE_METAL and BARE_METAL_LINUX_KERNEL execution environments.

As an example, the code below shows the new activity for Bare Metal debug of the Cortex-A15_0 core.

Notice that the dtsl_config parameter points to the new DtslScript_DSTREAM_ST class which provides the DTSL configuration when debugging with a DSTREAM-ST unit.


            <activity> id="ICE_DEBUG" type="Debug">
               <name> language="en">Debug Cortex-A15_0</name>
               <xi:include href="../../../Include/dstream_st_activity_description_bm.xml"/>
               <xi:include href="../../../Include/dstream_st_connection_type.xml"/>
               <core connection_id="Cortex-A15_0" core_definition="Cortex-A15"/>
               <param default="DtslScript_DSTREAM_ST" id="dtsl_config" type="string" visible="false"/>
            </activity>
      
       

Then, create similar entries to define activities for the A15_1 and A15x2 SMP cores in the BARE_METAL environment and also create three analogous entries for the BARE_METAL_LINUX_KERNEL environment.

Rebuilding the configuration database at this point creates a new debug configuration for the Arm Versatile Express A15x2 platform.

You can view the trace capture options that you specified in the DtslScript_DSTREAM_ST class when you open the DTSL options dialog.

DTSLOptionsDialog

At this point, we have only specified how the options look in the user interface. The next steps look at how to configure the DSTREAM-ST trace capture DTSL objects.

Configuring the DSTREAM-ST DTSL Objects

The DTSL class which represents the trace capture device for DSTREAM-ST is DSTREAMSTStoredTraceCapture.

You must import this DTSL class into the DTSL script.

At the top of the dtsl_config_script.py DTSL Jython script, add from com.arm.debug.dtsl.components import DSTREAMSTStoredTraceCapture.

As the configuration inherits the DSTREAM DtslScript class, it constructs a DSTREAMTraceCapture object which is the trace capture object for DSTREAM.

Next, modify the script to construct the DSTREAMSTStoredTraceCapture object when the DtslScript_DSTREAM_ST configuration is created. To do this, wrap the creation of the DSTREAMTraceCapture device in a function which can then be overridden. Doing so creates two trace captures objects – a DSTREAMTraceCapture object for DSTREAM configurations and a DSTREAMSTStoredTraceCapture for DSTREAM-ST configurations.

In the DtslScript class, modify the discoverDevices() function by replacing self.DSTREAM = DSTREAMTraceCapture(self, "DSTREAM") with self.createDSTREAM().

Then, introduce the new function:


            def createDSTREAM(self):
                self.DSTREAM = DSTREAMTraceCapture(self, "DSTREAM")
        

Then, in the DtslScript_DSTREAM_ST class override this method to construct the DSTREAM-ST trace capture object with the function:

def createDSTREAM(self):
                       self.DSTREAM = DSTREAMSTStoredTraceCapture(self, "DSTREAM")

You also need to override setupDSTREAMTrace function from the parent class which is called after the trace capture device is constructed and is used to configure the device.

The setupDSTREAMTrace configuration is very similar to the one used in the parent class.

So, copy it and then make a single modification, removing line self.DSTREAM.setTraceMode(DSTREAMTraceCapture.TraceMode.Continuous)as the DSTREAM-ST DTSL trace capture device does not have a configurable trace mode.

At this point, the DTSL object should look similar to the below code:


  class DtslScript_DSTREAM_ST(DtslScript):
    @staticmethod
    def getOptionList():
        return [
            DTSLv1.tabSet("options", "Options", childOptions=[
            DTSLv1.tabPage("traceBuffer", "Trace Buffer", childOptions=[
                DTSLv1.radioEnumOption(
                        name='traceCapture',
                        displayName = 'Trace capture method',
                        description="Specify how trace data is to be collected",
                        defaultValue="none",
                        setter=DtslScript.setTraceCaptureMethod,
                        values = [
                            ("none", "None"),
                            ("ETB", "On Chip Trace Buffer (ETB)"),
                            ("DSTREAM", "Streaming Trace")
                        ]
        ),
       ],
       DTSLv1.tabPage("cortexA15", "Cortex-A15", childOptions=[ 
 

...same as for DSTREAM...

      
      def createDSTREAM(self):
        self.DSTREAM = DSTREAMSTStoredTraceCapture(self, "DSTREAM")
 
      def setupDSTREAMTrace(self, portwidth):
        '''Setup DSTREAM trace capture'''

        # configure the TPIU for continuous mode
        self.tpiu.setFormatterMode(FormatterMode.CONTINUOUS)
        self.tpiu.setPortSize(portwidth)

        self.DSTREAM.setPortWidth(portwidth)
 
        # register other trace components
        self.DSTREAM.setTraceComponentOrder([ self.funnel0, self.tpiu ])
 
        # register the DSTREAM with the configuration
        self.addTraceCaptureInterface(self.DSTREAM)
 
        # automatically handle connection/disconnection to trace components
        self.addManagedTraceDevices("DSTREAM", [ self.funnel0, self.outCTI, self.tpiu, self.DSTREAM ])
 
        # register trace sources
        self.registerTraceSources(self.DSTREAM)

  

The configuration is almost complete. Now configure the port width for TPIU and DSTREAM for the DSTREAMSTStoredTraceCapture device as it accepts a narrower range of widths than an analogous DSTREAM capture device.

Adding configurable port width and trace buffer size

Configurable port width

The port width for the TPIU and the DSTREAMSTStoredTraceCapture device must be in the 1 – 4 range. The port width must also be made configurable and enforce a sensible default value.

To add a configurable port width, first, move the port width configuration lines from the setupDSTREAMTrace class into a new function and call that instead.

So, in the setupDSTREAMTrace class add: self.setPortWidth(portwidth). And add to the class DSTREAMSTStoredTraceCapture the function:


    def setPortWidth(self, portWidth):
        self.tpiu.setPortSize(portWidth)
        self.DSTREAM.setPortWidth(portWidth)

Then, modify the options list again to add a drop-down box enumerating all the possible valid port widths. The trace capture option ("DSTREAM", "Streaming Trace") becomes ("DSTREAM", "Streaming Trace", DtslScript_DSTREAM_ST.getDSTREAMOptions()).

Which calls the function that populates a drop-down box with the values 1 through 4, with 4 being the default.

            
   @staticmethod
    def getDSTREAMOptions():
            return DTSLv1.infoElement(
                "dstream", "", "", childOptions=[
                    DTSLv1.enumOption('tpiuPortWidth', 'TPIU port width', defaultValue="4",
                       values = [("1", "1 bit"), ("2", "2 bit"), ("3", "3 bit"), ("4", "4 bit")],
                                           isDynamic=False),

Finally, to the optionValuesChanged function in the DtslScript class which updates the options each time the configuration is changed, add the below lines:

            
                   dstream_opts = "options.traceBuffer.traceCapture.dstream"
                     portWidthOpt = self.getOptions().getOption(dstream_opts + ".tpiuPortWidth")
                     if portWidthOpt:
                     portWidth = self.getOptionValue(dstream_opts + ".tpiuPortWidth")
                     self.setPortWidth(int(portWidth))

This calls setPortWidth initially with the default value, then with whatever value is selected in the port width drop-down list.

For example:

DTSLOptionDropDown

Configurable Trace Buffer Size (optional)

In a similar way, you can configure the size of the trace buffer on the host machine filled by DSTREAM-ST streaming trace.

You can add a new function to configure the buffer size which sets the max capture size for the DSTREAM-ST trace capture device in bytes. If this setting is not configured, the default value is 4GB (4*1024*1024*1024). The lowest possible value is 64MB and the maximum can be any multiple of 64MB, and is only limited by the hard-disk space on your machine.

            
       def setTraceBufferSize(self, mode):
        '''Configuration option setter method for the trace cache buffer size'''
        cacheSize = 64*1024*1024
        if (mode == "64MB"):
            cacheSize = 64*1024*1024
        if (mode == "128MB"):
            cacheSize = 128*1024*1024
        if (mode == "4GB"):
            cacheSize = 4*1024*1024*1024
        if (mode == "128GB"):
            cacheSize = 128*1024*1024*1024
 
        self.DSTREAM.setMaxCaptureSize(cacheSize)

Now, add DTSL options to mirror the possible values.

So, getDSTREAMOptions becomes:

            
    @staticmethod
    def getDSTREAMOptions():
            return DTSLv1.infoElement(
                "dstream", "", "",
                childOptions=[
                   DTSLv1.enumOption('tpiuPortWidth', 'TPIU port width', defaultValue="4",
                       values = [("1", "1 bit"), ("2", "2 bit"), ("3", "3 bit"), ("4", "4 bit")],
                                           isDynamic=False),
                   DTSLv1.enumOption('traceBufferSize', 'Trace buffer size', defaultValue="4GB",
                        values = [("64MB", "64MB"), ("128MB", "128MB"), 
                                                    ("4GB", "4GB"), ("128GB", "128GB")], isDynamic=False)
            ]
         )
         

And add another callback to optionValuesChanged:

                    
        traceBufferSizeOpt = self.getOptions().getOption(dstream_opts + ".traceBufferSize")
        if traceBufferSizeOpt:
           traceBufferSize = self.getOptionValue(dstream_opts + ".traceBufferSize")
           self.setTraceBufferSize(traceBufferSize)

Conclusion

At this point your configuration is complete and now supports DSTREAM-ST full debug and trace capture with configurable port width and trace buffer size options.

DTSLOptionsConfigured

 

Frequently Asked Questions

I am not getting any trace from my DSTREAM-ST!

First, ensure that the self.setDSTREAMTraceEnabled(true) function is called when the "Streaming Trace" is set as your trace capture device. This is specified through the setter DtslScript.setTraceCaptureMethod in the DTSL options list.

Secondly ensure the value for "dtsl_tracecapture_option" in your project_types.xml corresponds to the path of the trace capture device when you have defined your DTSL options. This depends on how your options are nested and may vary between configurations. In this example, the "traceCapture" device belongs to the Trace Buffer tab in the Options tab page, so in the project_types.xml it is as follows:

<param default="options.traceBuffer.traceCapture" id="dtsl_tracecapture_option" type="string" visible="false"/>

I'm getting an error : Error running DTSL script: ('DSTREAM', 'Streaming Trace', dstream: DISPLAY - ) in values argument is not a valid enum value

When adding trace capture devices with child elements like the Streaming Trace, which has enumerations for TPIU port with and trace buffer size, it is necessary to use DTSLv1.radioEnumOption rather than a DTSLv1.enumOption as the latter does not permit child elements.

For troubleshooting other issues with your DSTREAM-ST, see Troubleshooting your DSTREAM-ST unit.