3.9. Accessing the debug interface from sc_main()

The CADI interface is typically used by attached debuggers. The interface can, however, be directly accessed from the top-level application that creates and connects the modules. This might be done, for example, to test the CADI interface or to write a customized debug function.

Example 3.23 shows the CADI methods that must be created for the component:

Example 3.23. CADI callback used by main()

class TopCADICallbackObj : public CADICallbackObj
{
public:
    TopCADICallbackObj ()     { } 
     ~TopCADICallbackObj ()    { } 
  
    virtual uint32_t appliOpen(const char *sFileName, const char *mode) 
    { 
        return 0; 
    } 
 
    virtual void appliInput (uint32_t streamId, uint32_t count,
                  uint32_t *actualCount, char *buffer) 
    { 
        // return value to debugger 
        static int id = 100; 
        sprintf (buffer, "Input:%d\n", id); 
        (* actualCount) = (uint32_t) (strlen (buffer) + 1); 
        ++ id; 
    } 
 
    virtual void appliOutput(uint32_t streamId, uint32_t count, 
                 uint32_t * actualCount, const char *buffer) 
    { 
        //output text from debugger
        char * tmp = new char [count + 1]; 
        memcpy (tmp, buffer, count); 
        tmp [count] = 0; 
        printf (tmp); 
        (* actualCount) = count; 
    } 
 
    virtual uint32_t appliClose(uint32_t streamID) 
    { 
        return 0; 
    } 
 
    virtual void doString(char *stringArg)    { } 
 
    virtual void modeChange(uint32_t newMode, CADIBptNumber_t bptNumber) 
    { 
        if (newMode == CADI_EXECMODE_Stop) 
        { 
            // we are done, finish execution 
            SEMINC(semaphore); 
        } 
    } 
 
    virtual void reset(uint32_t resetLevel)    { } 
 
    virtual void cycleTick(void)     { } 
 
    virtual void killInterface(void)  { }
};

Example 3.24 shows the code that must be added to the top-level application to access CADI data:

Example 3.24. CADI code in main function

int sc_main (int argc, char *argv[])
{
    //Instantiate the modules
    .
    .
    .
    Slave_casi * s1 = new Slave_casi("Slave1");
    Slave_casi * s2 = new Slave_casi("Slave2");

    // setup CADI    
    char enable [CADI_CB_Count];
    memset (& enable[0], 1, sizeof (enable));
    s1->getCADI ()->CADIXfaceAddCallback (new TopCADICallbackObj (), enable);
    s2->getCADI ()->CADIXfaceAddCallback (new TopCADICallbackObj (), enable);
    
    //Call init functions and setup memory map interface
    .
    .
    .
    //Connect the ports, call all interconnect functions, and reset
    .
    .
    .
    // start simulation
    sc_start (0x8000); // stops at 0x4000
    .
    .
    .
    // get CADI object from port and read register data
    CADI * cadi1 = s1->getCADI ();

    uint32_t actual;
    static CADIRegGroup_t regGroups [2];
    result = cadi->CADIRegGetGroups(0, features.nrRegisterGroups, 
                  & actualCount, regGroups);
    if (result != CADI_STATUS_OK || actualCount < 1)
    {
        printf("CADIRegGetGroups call ..... failed!\n");
    }

    CADIRegGroup_t & regGroup = regGroups [0];
    static CADIRegInfo_t regs [2];
    result = cadi1->CADIRegGetMap (regGroups [0].groupID, 0, 2, & actual, regs);
    if (result != CADI_STATUS_OK || actualCount < 1)
    {
        printf("CADIRegGetMap call ..... failed!\n");
    }

    CADIRegInfo_t & regInfo = regInfos [0];
    static CADIReg_t regs [1];
    regs [0].regNumber = regInfo.regNumber;
    CADIReg_t & reg = regs [0];
    SEMOPEN (semaphore);
    cadi->CADIExecContinue ();

    CADIReg_t reg;
    memset (& reg, 0, sizeof (CADIReg_t));
    reg.regNumber = regs [1].regNumber;
    cadi1->CADIRegRead (1, & reg, & actual, 0);
    uint32_t tmp32 = 0;
    tmp32 = (tmp32<<8) | reg.bytes[3];
    tmp32 = (tmp32<<8) | reg.bytes[2];
    tmp32 = (tmp32<<8) | reg.bytes[1];
    tmp32 = (tmp32<<8) | reg.bytes[0];

    printf ("CADI reg 0x%x\n", tmp32);

    // terminate components
    .
    .
    .

    cadi->CADIExecStop ();
    SEMDEC (semaphore);
    SEMCLOSE (semaphore);
    printf ("Closing CADI\n");
    cadi->CADIXfaceRelease (& refCount);
    DestroyCADIFactory (factory);

    fflush (stdout);
    fflush (stderr);
    return 0;
}

The module s1 is an instance of a Slave_casi component and it must provide the getCADI() function and CADI object (based on CADIBase) that enables accessing the registers and memory of the module as shown in Example 3.25.

Example 3.25. Slave_casi CADI functions

Slave_casi::Slave_casi(sc_module_name name, CASIModuleIF * parent)
                      : CASIModule(name, parent)
{
    // instantiate ports
    .
    .
    .
    // Create CADI object
    cadi = new CADISlave (this);
    .
    .
    .

}

CADI* Slave_casi::getCADI()
{
    return cadi;
}

The CADISlave class contains the access functions as shown in Example 3.26.

Example 3.26. CADISlave CADI functions

CADIReturn_t CADISlave::CADIRegGetGroups( uint32_t groupIndex,
        uint32_t desiredNumOfRegGroups,	uint32_t* actualNumOfRegGroups,
        CADIRegGroup_t* grp )
{
    if ( groupIndex >= GROUP_COUNT )
    {
        return CADI_STATUS_IllegalArgument;
    }

    uint32_t	i;
    for( i = groupIndex; ( i < groupIndex + desiredNumOfRegGroups ) && ( i <
        GROUP_COUNT ); i++ )
    {
        grp[i] = regGroup[i];
    }
    *actualNumOfRegGroups = i - groupIndex;
    return CADI_STATUS_OK;
}

CADIReturn_t CADISlave::CADIRegGetMap( uint32_t groupID, uint32_t regIndex,
           uint32_t registerSlots, uint32_t* registerCount, CADIRegInfo_t* reg )
{
    if ( groupID >= GROUP_COUNT )
    {
        return CADI_STATUS_IllegalArgument;
    }
    uint32_t 	i;
    uint32_t	start = regIndex + CADISlave_group_info[groupID].start;
    uint32_t	end = regIndex + CADISlave_group_info[groupID].end;
    for ( i = 0; ( i < registerSlots ) && ( start + i <= end ); i++ )
    {
        reg[i] = regInfo[start + i];
    }
    *registerCount = i;
    return CADI_STATUS_OK;
}

CADIReturn_t CADISlave::CADIRegRead( uint32_t regCount, CADIReg_t* reg, 
                     uint32_t* numRegsRead, uint8_t doSideEffects )
{
    UNUSEDARG(doSideEffects);
    uint32_t	i;
    for ( i = 0; i < regCount; i++ )
    {
		uint16_t tmp16 = 0;
		uint32_t tmp32 = 0;
		uint64_t tmp64 = 0;
        switch (reg[i].regNumber)
        {
        case 0:
            //64-bit Register
            tmp64 = target->r_reg2;
            reg[i].bytes[0] = (uint8_t)((tmp64 >> 0) & 0xff);
            reg[i].bytes[1] = (uint8_t)((tmp64 >> 8) & 0xff);
            reg[i].bytes[2] = (uint8_t)((tmp64 >> 16) & 0xff);
            reg[i].bytes[3] = (uint8_t)((tmp64 >> 24) & 0xff);
            reg[i].bytes[4] = (uint8_t)((tmp64 >> 32) & 0xff);
            reg[i].bytes[5] = (uint8_t)((tmp64 >> 40) & 0xff);
            reg[i].bytes[6] = (uint8_t)((tmp64 >> 48) & 0xff);
            reg[i].bytes[7] = (uint8_t)((tmp64 >> 56) & 0xff);
            break;
        case 1:
            //32-bit Register
            tmp32 = target->r_reg3;
            reg[i].bytes[0] = (uint8_t)((tmp32 >> 0) & 0xff);
            reg[i].bytes[1] = (uint8_t)((tmp32 >> 8) & 0xff);
            reg[i].bytes[2] = (uint8_t)((tmp32 >> 16) & 0xff);
            reg[i].bytes[3] = (uint8_t)((tmp32 >> 24) & 0xff);
            break;
        case 2:
            //16-bit Register
            tmp16 = target->r_reg0;
            reg[i].bytes[0] = (uint8_t)((tmp16 >> 0) & 0xff);
            reg[i].bytes[1] = (uint8_t)((tmp16 >> 8) & 0xff);
            break;
        case 3:
            //8-bit Register
            tmp16 = target->r_reg1;
            reg[i].bytes[0] = (uint8_t)((tmp16 >> 0) & 0xff);
            break;
        default:
            break;
        }
    }
    *numRegsRead = regCount;
    return CADI_STATUS_OK;
}
Copyright © 2007 ARM Limited. All rights reserved.ARM DUI 0359B
Non-Confidential