ARM Technical Support Knowledge Articles

How can I use SCADI from a LISA+ component to model a synchronous watchpoint

Applies to: Fast Models



The purpose of using SCADI and synchronous stop from within a LISA+ component is to be able to implement 'external breakpoints'. Such breakpoints can stop the simulation upon complex conditions which appear in peripheral components. For example writing invalid register values or writing to invalid or reserved peripheral registers or other invalid conditions within a peripheral. This example is designed to illustrate how SCADI can be used from within a LISA+ component.

The System

The system contains a Cortex-A8 model (this can be substituted for any other ARM core model), instruction RAM (addr 0x0-0xfffffff) and a custom slave component, slave.lisa (0x10000000-0x1000ffff).

Slave Component

This component implements a single RW register (at offset 0x0). When read the slave returns the value of this register, when written to the slave performs a synchronous stop of the simulation, in addition to storing the value.

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

1) Setting syncLevel on cores

To enable the component to synchronously stop any core, the syncLevel of all cores must be set to syncLevel 2 (POST_INSN_IO).  To do this a CADI pointer for each core need to be obtained.

First step is to obtain the global interface:

        // get access to a CAInterface
        eslapi::CAInterface * caif = getGlobalInterface();
        if (caif == 0)
            std::cerr << "Global interface not found!\n";

From this the MTI SystemTraceInterface can be used to obtain a list of component within the system:

        // get access to MTI interface (SystemTraceInterface)
        caif = caif->ObtainInterface(MTI::SystemTraceInterface::IFNAME(), MTI::SystemTraceInterface::IFREVISION(), 0);
        if (caif == NULL)
            std::cerr << "MTI interface not found!\n";
        MTI::SystemTraceInterface * mti = static_cast<MTI::SystemTraceInterface*>(caif);

        // check for at least 1 component
        uint32_t number_of_components = mti->GetNumOfTraceComponents();
        if (!number_of_components)
            std::cerr << "Error, no mti components\n";

The MTI interface can be used to obtain a CADI pointer.  Using SimpleCADI, write to the syncLevelPostInsnIORegister register if present.

        // cycle through all components finding all the cores
        for (uint32_t i=0; i<number_of_components;i++)
            caif = mti->GetComponentTrace(i);
            caif = caif->ObtainInterface("eslapi.CADI2", 0, 0);
            if (caif == NULL)
                std::cerr << "CADI interface not found!\n";
            // if component has a syncLevel register it is a core
            if (simplecadi.hasRegister("syncLevel"))
                //set synclevel to syncLevelPostInsnIORegister
                simplecadi.regWrite("syncLevelPostInsnIORegister", 0);

2) Stopping synchronously

With the syncLevel's set for each core, the method by which the component halts the core is simple. a CADI or SCADI pointer is not required as the simHalt function is provided globally within LISA+.

        slave  behavior write(pv::WriteTransaction tx) : pv::Tx_Result
            if (tx.getAddress() == 0)
                simHalt();  // stop simulation
                mem = tx.getData32();
                return tx.writeComplete();
                return tx.generateSlaveAbort();

Example application

An example application is provided as assembler within the 'app' folder. A build script is also provided to aid rebuilding of the image. The application performs a single store to the slaves register then enters a idle loop.

Running the example

To run this example you need to perform the following steps:

1) build the example
2) build the application in the apps folder
3) launch Model Debugger, load the model and image build in 1) and 2)
4) run

When ran, the simulation will stop synchronously after the STR has completed

Why do I have to set the syncLevel? Why is a simple simHalt() not sufficient?

A simple simHalt() without setting the syncLevel POST_INSN_IO beforehand will also stop the simulation, but as the simulation is executed in chunks of instructions (called a quantum) rather than individual instructions, the simulation would only stop at the end of such a quantum. The effect would be that the simulation has run typically about 50-200 instructions past the point where the breakpoint happened. This is often undesirable. Setting the syncLevel to POST_INSN_IO makes the simulation stop precisely after all peripheral accesses.

Why is syncLevel=POST_INSN_IO not  the default? It seems so useful!

This is because the simulation gets slower with increasing syncLevels (increasign simulation accuracy and the default is the fastes mode of simulation. Users (LISA+ components) need to tell the simulator which restriction they need. The breakpoint could also be disabled by an end user in which case the syncLevel can be release to the default (OFF, 0).

Notes on implementing SCADI in LISA+

There are a few points to note when using SCADI from LISA+.

1) getGlobalInterface should not be called in the init behaviour as the required configuration is not present at that time. The earliest time which this should be called in is within reset.

2) to obtain a SCADI pointer, you must first obtain a pointer to that component's MTI component trace interface.

3) CADIExecStop can be called on any component's SCADI interface as this effects the simulation as a whole. For other SCADI commands the specific component's SCADI interface is required.

Attachments: scadi_from_lisa_system.png ,

Article last edited on: 2013-08-27 13:32:50

Rate this article

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