You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
149 lines
8.6 KiB
149 lines
8.6 KiB
Attaching External Custom Decoders {#custom_decoders}
|
|
==================================
|
|
|
|
@brief A description of the C API external decoder interface.
|
|
|
|
Introduction
|
|
------------
|
|
|
|
An external custom decoder is one which decodes a CoreSight trace byte stream from a source other
|
|
than an ARM core which cannot be decoded by the standard built-in decoders within the library.
|
|
|
|
An example of this may be a trace stream from a DSP device.
|
|
|
|
The external decoder API allows a suitable decoder to be attached to the library and used in the
|
|
same way as the built-in decoders. This means that the external decoder can be created and destroyed
|
|
using the decode tree API, and will integrate seamlessly with any ARM processor decoders that are part
|
|
of the same tree.
|
|
|
|
An external decoder will be required to use three standard structures:-
|
|
|
|
- `ocsd_extern_dcd_fact_t` : This is a decoder "factory" that allows the creation of the custom decoders.
|
|
- `ocsd_extern_dcd_inst_t` : This structure provides decoder data to the library for a single decoder instance.
|
|
- `ocsd_extern_dcd_cb_fns` : This structure provides a set of callback functions allowing the decoder to use library functionality in the same way as built-in decoders.
|
|
|
|
These structures consist of data and function pointers to allow integration with the library infrastructure.
|
|
|
|
Registering A Decoder
|
|
---------------------
|
|
|
|
A single API function is provided to allow a decoder to be registered with the library by name.
|
|
|
|
ocsd_err_t ocsd_register_custom_decoder(const char *name, ocsd_extern_dcd_fact_t *p_dcd_fact);
|
|
|
|
This registers the custom decoder with the library using the supplied name and factory structure.
|
|
As part of the registration function the custom decoder will be assigned a protocol ID which may be used in
|
|
API functions requiring this parameter.
|
|
|
|
Once registered, the standard API functions used with the built-in decoders will work with the custom decoder.
|
|
|
|
The Factory Structure
|
|
---------------------
|
|
This structure contains the interface that is registered with the library to allow the creation of custom decoder instances.
|
|
|
|
The mandatory functions that must be provided include:
|
|
- `fnCreateCustomDecoder` : Creates a decoder. This function will fill in a `ocsd_extern_dcd_inst_t` structure for the decoder instance.
|
|
- `fnDestroyCustomDecoder` : Destroys the decoder. Takes the `decoder_handle` attribute of the instance structure.
|
|
- `fnGetCSIDFromConfig` : Extracts the CoreSight Trace ID from the decoder configuration structure.
|
|
May be called before the create function. The CSID is used as part of the creation process to
|
|
attach the decoder to the correct trace byte stream.
|
|
|
|
`fnPacketToString` : This optional function will provide a human readable string from a protocol specific packet structure.
|
|
|
|
`protocol_id` : This is filled in when the decoder type is registered with the library. Used in some API
|
|
calls to specify the decoder protocol type.
|
|
|
|
|
|
|
|
Creating a Custom Decoder Instance
|
|
----------------------------------
|
|
|
|
Once the custom decoder factory has been registered with the library then using the decoder uses the standard creation API:-
|
|
|
|
`ocsd_dt_create_decoder(const dcd_tree_handle_t handle, const char *decoder_name, const int create_flags,
|
|
const void *decoder_cfg, unsigned char *pCSID)`
|
|
|
|
|
|
This creates a decoder by type name in the current decode tree and attaches it to the trace data stream associated with a CoreSight trace ID extracted from
|
|
the trace configuration.
|
|
|
|
To create a custom decoder instance simply use the custom name and a pointer to the custom configuration structure.
|
|
|
|
Calling this on a custom decoder name will result in a call to the factor function `fnCreateCustomDecoder` function:-
|
|
`ocsd_err_t CreateCustomDecoder(const int create_flags, const void *decoder_cfg, const ocsd_extern_dcd_cb_fns *p_lib_callbacks, ocsd_extern_dcd_inst_t *p_decoder_inst)`
|
|
|
|
This will first require that the `ocsd_extern_dcd_inst_t` structure is populated.
|
|
|
|
There is are two mandatory function calls in this structure that may be called by the library
|
|
|
|
`fnTraceDataIn` : the decoder must provide this as this is called by the library to provide the
|
|
raw trace data to the decoder.
|
|
|
|
`fn_update_pkt_mon` : Allows the library to communicate when packet sink / packet monitor interfaces are attached to the decoder and in use.
|
|
|
|
The decoder creation process will also fill in the additional information to allow the library to correctly call back into the custom decoder using the `decoder_handle` parameter.
|
|
|
|
Secondly the library will provide a structure of callback functions - `ocsd_extern_dcd_cb_fns` - that the decoder can use to access standard library functionality.
|
|
This includes the standard error and message logging functions, the memory access and ARM instruction decode functions, plus the current output sink for generic
|
|
trace elements generated by the decoder. The decoder is not required to use these functions - indeed the ARM instruction decode will not be useful to none ARM
|
|
architecture decoders, but should where possible use these functions if being used as part of a combined ARM / custom decoder tree. This will simplify client
|
|
use of the external decoders.
|
|
|
|
The `create_flags` parameter will describe the expected operational mode for the decoder. The flags are:-
|
|
- `OCSD_CREATE_FLG_PACKET_PROC` : Packet processing only - the decoder will split the incoming stream into protocol trace packets and output these.
|
|
- `OCSD_CREATE_FLG_FULL_DECODER` : Full decode - the decoder will split the incoming stream into protocol trace packets and further decode and analyse these to produce generic trace output which may describe the program flow.
|
|
|
|
Finally the decoder creation function will interpret the custom configuration (`decoder_cfg`) and fill in the CoreSight Trace ID parameter `pCSID`
|
|
for this decoder instance. Decoder configuration structures describe registers and parameters used in programming up the trace source. The only
|
|
minimum requirement is that it is possible to extract a CoreSight trace ID from the configuration to allow the library to attach the correct byte
|
|
stream to the decoder.
|
|
|
|
|
|
Example : The echo_test decoder
|
|
--------------------------------
|
|
|
|
The echo_test decoder is provided to both test the C-API interfaces provided for using custom decoders and as a worked example for using these interfaces.
|
|
|
|
This decoder is initialised and created by the `c_api_pkt_print_test` program when the `-extern` command line option is used.
|
|
|
|
In order to use a custom decoder, the header files for that decoder must be included by the client as they are not part of the built-in provided by the standard library includes.
|
|
|
|
#include "ext_dcd_echo_test_fact.h" // provides the ext_echo_get_dcd_fact() fn
|
|
#include "ext_dcd_echo_test.h" // provides the echo_dcd_cfg_t config structure.
|
|
|
|
The `register_extern_decoder()` function in the test shows how simple the API is to use.
|
|
|
|
The implementation of the decoder provides an external function to get a factory structure.
|
|
|
|
p_ext_fact = ext_echo_get_dcd_fact();
|
|
|
|
Assuming this returns a structure then the decoder is registered by name.
|
|
|
|
if (p_ext_fact)
|
|
{
|
|
err = ocsd_register_custom_decoder(EXT_DCD_NAME, p_ext_fact);
|
|
}
|
|
|
|
After this the test uses the same code path as the built in decoders when testing the custom decoder.
|
|
The test function `ocsd_err_t create_decoder_extern(dcd_tree_handle_t dcd_tree_h)` is called if the test parameters indicate a custom decoder is needed.
|
|
This populates the custom configuration structure specific to the echo_test decoder (`echo_dcd_cfg_t`), then passes this plus the decoder name to the same `create_generic_decoder()` function used when testing the built in decoders.
|
|
|
|
|
|
static ocsd_err_t create_decoder_extern(dcd_tree_handle_t dcd_tree_h)
|
|
{
|
|
echo_dcd_cfg_t trace_cfg_ext;
|
|
|
|
/* setup the custom configuration */
|
|
trace_cfg_ext.cs_id = 0x010;
|
|
if (test_trc_id_override != 0)
|
|
{
|
|
trace_cfg_ext.cs_id = (uint32_t)test_trc_id_override;
|
|
}
|
|
|
|
/* create an external decoder - no context needed as we have a single stream to a single handler. */
|
|
return create_generic_decoder(dcd_tree_h, EXT_DCD_NAME, (void *)&trace_cfg_ext, 0);
|
|
}
|
|
|
|
From the test program perspective, these are the only changes made to the test program to test this decoder.
|
|
The `create_generic_decoder()` then uses the normal C-API calls such as `ocsd_dt_create_decoder()` and `ocsd_dt_attach_packet_callback()` to hook the decoder into the decode tree infrastructure.
|