ARM Technical Support Knowledge Articles

How do I use SCADI from a MTI plugin

Applies to: Fast Models

Answer

Introduction

The purpose of this example is to illustrate how SCADI can be used from within a MTI plugin. This plugin is based on the SimpleTracePlugin example provided with the Fast Models tool and illustrates how, using SCADI, core registers can be reliably read from within the plugin itself. Before SCADI was available, any reading of core registers within a MTI plugin was not guaranteed to contain up to date values.

The plugin will trace CORE_STORES which is triggered whenever the core executes a store instruction. When triggered, the plugin will compare the virtual address provided in the trace with each of the core's general purpose registers to determine which register contain the address.

System

The system used in this example is a Cortex-A9UP connected to 4gig of RAM. The SCADI functionality in the plugin is system agnostic, however, for simplicity, the SimpleTraceExample assumes the core is MTI component number 1 (which is the case in the provided system).

The plugin

This component makes use of the SimpleCADI helper file that is discussed in the following article.

During RegisterSimulation, the plugin obtains a SCADI pointer and sets the syncLevel for the core in addition to creating and registering the trace event. Within the plugins callback function, the plugin will read each of the core's general purpose register via SCADI and determine which register holds the address of the store.

Obtaining SCADI pointer

  // Get the System Trace Interface:
  ca_interface = ca_interface->ObtainInterface(SystemTraceInterface::IFNAME(),
                                               SystemTraceInterface::IFREVISION(), 0);
  if (!ca_interface)
    return CADI_STATUS_IllegalArgument;
  SystemTraceInterface *sti = static_cast<SystemTraceInterface *>(ca_interface);

  // Get Component Trace Interface of first component:
  ca_interface = sti->GetComponentTrace(1);
  ca_interface = ca_interface->ObtainInterface(ComponentTraceInterface::IFNAME(),
                                               ComponentTraceInterface::IFREVISION(), 0);
  if (!ca_interface)
    return CADI_STATUS_GeneralError;
  ComponentTraceInterface *cti = static_cast<ComponentTraceInterface *>(ca_interface);

  // Get the SCADI Interface:
  ca_interface = ca_interface->ObtainInterface("eslapi.SCADI2", 0, 0);
  if (!ca_interface)
    return CADI_STATUS_IllegalArgument;
  scadi = static_cast<eslapi::CADI*>(ca_interface);
  simplecadi.setCADI(scadi);  // pass scadi pointer to helper object

RegisterSimulation provides a CAInterface pointer to the plugin. Using this pointer individual trace components can be found. With the core found (MTI component 1 in this example), a SCADI pointer can be obtained. This pointer is then used in the SimpleCADI helper object.

Setting synclevel

  // register synlevel on core
  if (simplecadi.hasRegister("syncLevel"))
  {
    //set synclevel to syncLevelSyncStateRegister
    simplecadi.regWrite("syncLevelSyncStateRegister",0);
  }

When setting the syncLevel of a core, the desired trade off between performance and functionality needs to be made. To access core registers while the simulation is running a syncLevel of SyncState (1) is required. The syncLevel is set by writing to the syncLevelSyncStateRegister of the core.
The different SyncLevels are described here: http://infocenter.arm.com/help/topic/com.arm.doc.dui0423n/CHDFEHIA.html

Trace callback

  // obtain virtual address of store
  uint64_t vaddr = record->Get<uint32_t>(event_class, inst_vaddr_index);

  // check which register the address was located in
  for(int i =0;  i<12;i++)
  {
    if (vaddr == simplecadi.regRead(regnames[i]))
    {
      count[i]++;
      break;
    }
  }

Within the callback SCADI reads are performed via the SimpleCADI helper object. SimpleCADI already has the SCADI pointer for the core, so performs a standard CADIRegRead using this SCADI pointer. As the syncLevel has been set to SyncState, SCADI register reads will return the correct register value.

When one of the core's registers contain the same address value provided by the trace, the count for that register is incremented.

Displaying results

void
SimpleSCADIExample::Release()
{
    // print out statistics
    printf("Register count is:\n");
    for(int i=0;i<12;i++)
    {
        printf("%s %d\n",regnames[i], count[i]);
    }
    delete this;
}

The results, number of times each register has been used for the address, is printed out to stdout. This is done when the plugin is released, which is performed when the simulation is closed.

Running the example

  1. Build the system
  2. Build the plugin
  3. Open a console and launch model_shell with the following commands:
  model_shell --plugin plugin\Win32\Debug_2010\SimpleTrace.dll \
              --model  system\Win32-Debug-VC2010\cadi_system_Win32-Debug-VC2010.dll \
              -a       app\dhystone.axf 

The model will execute Dhrystone and once finished the plugin will print out the results, for example:

Register count is:
R0 121842
R1 80678
R2 60067
R3 4
R4 21753
R5 6
R6 20000
R7 2
R8 28
R9 2
R10 0
R11 0

Attachments: SCADITraceExample.png , SCADITraceExample.zip

Article last edited on: 2013-08-27 13:36:51

Rate this article

[Bad]
|
|
[Good]
Disagree? Move your mouse over the bar and click

Did you find this article helpful? Yes No

How can we improve this article?

Link to this article
Copyright © 2011 ARM Limited. All rights reserved. External (Open), Non-Confidential