ARM Technical Support Knowledge Articles

How can I exposing SystemC resources via CADI

Applies to: Fast Models

Answer

Introduction

A SystemC component's resources can be exposed via CADI and displayed in a debugger. This can be quite useful when it comes to verifying and debugging SystemC exported models. The purpose of this example is to illustrate how SystemC resources can be viewed in a CADI Debugger. In order to accomplish this, a dummy component is added to the LISA system for debug accesses. The Dummy LISA component mirrors resources in the SystemC component and exposes them via CADI using the standard mechanism in LISA. It is responsible for obtaining the required information from the SystemC component to be able to populate these mirrored resources. For the sake of simplicity, this example exposes just a single memory mapped register (SystemC) to the CADI Debugger.

The System

The example system contains:

Debug Access Component

As mentioned before, the debug access component mirrors the SystemC resources i.e. a register in this example. This component implements a single virtual RW register. Accesses to this register from a debugger are forwarded to the SystemC component and thus, exposing the SystemC register value to the CADI debugger. The component also refreshes the CADI view whenever the value stored in the SystemC register is updated.

In order to expose the register in CADI, the REGISTER keyword is required in the resources section of the LISA code for the debug access component. The bit-width, type and other optional parameters can be specified for the register when declaring this resource. The code snippet below declares a virtual register called REG0 of type unsigned int and a bit-width of 32 bits.

  resources
  {
     REGISTER { type(uint),
                virtual(true),
                bitwidth(32),
                read_function(register_read),
                write_function(register_write)
              } REG0;
  }

To allow the debug component to access information from the SystemC component, it needs to generate transactions. This is can be achieved by instantiating a pointer of type pv::TransactionGenerator and invoking the createTransactionGenerator() function. This creates a TransactionGenerator object created within the PVBusMaster and returns a pointer to it.

  pv::TransactionGenerator *tg;

  tg = pvcontrol.createTransactionGenerator();

The debug component's register needs to update itself with the current value stored in SystemC register. This can be done by appropriately defining the register's (REG0) debug access behaviors. These debug access behaviors (below) access the Register value in the SystemC component by creating transactions (as mentioned above) using the tg->read() and tg->write() access functions.

    behavior register_write(uint32_t id, const uint64_t *data, bool doSideEffects) : AccessFuncResult
     {
        tg -> write(0x0, pv::ACCESS_32_BITS, (uint32_t*)data);
        return ACCESS_FUNC_OK;
     }

     behavior register_read(uint32_t id, uint64_t *data, bool doSideEffects) : AccessFuncResult
     {
        tg -> read(0x0, pv::ACCESS_32_BITS, (uint32_t*)data);
        return ACCESS_FUNC_OK;
     }

In addition to updating the register values, at times the CADI debugger view must also be refreshed so that the new values are displayed. In this example, the SystemC component drives the "refresh" port on the debug access component. When ever a high signal from the SystemC component is detected on the refresh port, the debug access component refreshes the CADI view. The signal is driven high whenever the value stored in the SystemC register has been updated.

    internal slave port<Signal> refresh
    {             
        behavior setValue(sg::Signal::State state):void
        {               
            if (state == sg::Signal::Set)
            {
                // Tell attached debuggers to refresh their register view
                cadiPort__.cadiRefresh(eslapi::CADI_REFRESH_REASON_REGISTERS);  
            }
        }

    }

SystemC Component

The SystemC component has a single memory mapped register and 3 ports in total. These are described below:

    /* Module ports */
        amba_pv::amba_pv_slave_socket<64> amba_pv_s;
        amba_pv::amba_pv_slave_socket<64> debug_amba_pv_s;
        amba_pv::signal_master_port<bool> debug_refresh_signal;

The component implements read, write, debug read and debug write access functions to allow access to it's register. These are also invoked by the debug component to access the SystemC component's register. The write access function is used to modify the SystemC component's register's value. This in turn also drives the debug_refresh_signal port to high which forces the debug component to refresh the CADI view. The code snippet below shows how the write access function is defined.

  /* Write access */
  amba_pv::amba_pv_resp_t SCADI_Component::write(int socket_id,
                                                 const sc_dt::uint64 & addr, 
                                                 unsigned char * data,
                                                 unsigned int size, 
                                                 const amba_pv::amba_pv_control * ctrl, 
                                                 unsigned char * strb, 
                                                 sc_core::sc_time & t)
  {  
    switch (addr)
    {  
      case REG_ADDR:  
        SCADI_Component::Register = (* reinterpret_cast<unsigned int *>(data));
        debug_refresh_signal.set_state(true);
        std::cout << "Data Stored = " << std::hex << SCADI_Component::Register << std::endl;
        debug_refresh_signal.set_state(false);
        break;

      default:
        std::cout << "ERROR\t" << name() << ": received write request "
                  << "with input address out of range: " << std::showbase 
                  << std::hex << addr << std::endl;
        return (amba_pv::AMBA_PV_SLVERR);
    } 
    return (amba_pv::AMBA_PV_OKAY);
  }

 

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 SystemC component's register then enters a idle loop.

Running the example

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

1) build the example using the provided Makefile.
2) build the application in the apps folder using the provided batch file (build.bat).
3) Launch the resulting executable via command line using the following command:

    SysC_Component.exe  -a  app\image.axf  -S

Attachments: Dummy.png , system.png , MI-exposingSysCResources.zip

Article last edited on: 2013-08-27 13:31:49

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