| |||
| Home > The Cycle Accurate Debug Interface > 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;
}