3.5. Accessing memory

Memory accesses are performed by the CADI methods CADIMemRead() and CADIMemWrite(). In contrast to register accesses, a memory access is not described by a data structure but by several parameters that must be passed to the methods.

The prototype of CADIMemRead(), for example, is:

CADIReturn_t CADIMemRead( CADIAddrComplete_t startAddress,
                            uint32_t unitsToRead, 
                            uint32_t unitSizeInBytes, 
                            uint8_t *data,
                            uint32_t *actualNumOfUnitsRead, 
                            uint8_t doSideEffects);    

The start address is specified in the location.add data member of an object of type CADIAddrComplete_t.

The unitsToRead and unitSizeInBytes parameters specify the number and the size of units that are accessed. The size of a unit is specified in bytes and must be a supported multiple of the Minimum Access Size (MAU). A list of the supported multiples can be obtained from the corresponding memory block information.


Memory accesses must consider invariance. The unitSizeInBytes memory space property specifies the number of bytes that are treated as one unit. The coherence of these bytes is preserved, especially if converting endianess.

The total memory accessed in bytes is equal to the number of access units times their size in bytes. The data buffer used to perform the memory access is an array of uint8_t that must have exactly the same size as the complete access size.

The number of actually read or written access units is returned. If the memory access is completely successful, the value identified by actualNumOfUnitsRead value equals the number of units requested in unitsToRead.


The requested number of units is not the size in bytes.

If an access succeeds partially, the returned number equals the one of completed units and the contents of data is valid for additional processing. An example for such a situation is the attempt to access memory that is not part of a memory block. This might happen if performing an access that exceeds a valid memory range.

As with data buffers for register accesses, data buffers for memory accesses are always used with little endian format.

Memory accesses can be optionally performed depending on the corresponding parameter passed to CADIMemRead() or CADIMemWrite(). As for register accesses, the target ultimately must decide which side effects can be omitted.

For CADIMemRead(), an example of a side effect is clear-on-read. If a read is done with the doSideEffects parameter set to false, all side effects must be omitted. Such a debug read can not interfere with the execution of the target.

A side effect during writing a memory might be, for example, the usage of a memory-mapped register whose contents controls the mode of a certain component. If this value is changed, the component must perform this side effect even if doSideEffects is set to false. If the side effect was not done, the simulated target would behave incorrectly. Example 3.7 shows write accesses to memory:

Example 3.7. Writing to memory

eslapi::CADI* cadi;
eslapi::CADIMemSpaceInfo_t mem_space;
eslapi::CADIMemBlockInfo_t mem_block;

//...fill the above declared variables with feasible data...

//preparing a write access to the beginning of the memory block

eslapi::CADIAddrComplete_t startAddress;
startAddress.location.space = mem_space.memSpaceId;
startAddress.location.addr = mem_block.startAddr;

//writing 256 words of 4 byte
uint32_t unitsToWrite = 256;
uint32_t unitSizeInBytes = 4;
uint32_t actualNumOfUnitsWritten = 0;

uint32_t completeAccessInBytes = unitsToWrite * unitSizeInBytes;
uint8_t* data = new uint8_t[completeAccessInBytes]();

//...filling data buffer "data"...
eslapi::CADIReturn_t status;
status = cadi->CADIMemWrite(startAddress, unitsToWrite, unitSizeInBytes,
                            data,&actualNumOfUnitsWritten, 0); 
//do no side effects
//...check status and actualNumOfUnitsWritten...
delete[] data;

Copyright © 2008-2011 ARM. All rights reserved.ARM DUI 0444H