| |||
| Home > Components > Resources section > Memory | |||
Memory resources are C-array-like constructs that make their contents visible to a debugger. They are always declared using the array syntax where the size of the array is the size of the memory.
The parameters listed in Table 2.3 can be given to memories:
Table 2.3. Parameters for memory, bus, and address space
| Parameter | Type | Default | Description |
|---|---|---|---|
allow_unaligned_access | boolean | false | Allow unaligned access. If this is true then accesses that are not naturally aligned, such as a 32-bit access on a non32-bit boundary, are allowed and have the expected result. If this is false such unaligned accesses are not allowed. |
attribute | access type | read_write | Access type as one of:
|
description | string | "" | Description of the space |
endianness | big or little | little | Select between little and big endianness. |
executable | boolean | false | This flag identifies memory blocks that can hold executable code. |
mau_size | integer | 8 | Size of the Minimum Addressable Unit (MAU) in bits. Admissible values are 8, 16, 32, and 64. |
paged | boolean | true | Allow use of true paged memory. This means
memory is not allocated completely at instantiation time, but instead
in pages on demand. This typically results in lower overall memory usage
but leads to slower memory access. If the array size is > 0x10000,
paging is enforced for the memory and the parameter is ignored. |
read_function | string | none | Name of the debug read access behavior. |
space_id | integer | -1 | Specifies the memory space id. If not defined, space_id is
automatically generated. |
supported_multiples_of_mau | string | 1 | Permitted multiples of MAU for memory accesses. Multiple values must be separated by commas. |
virtual | boolean | false | Optimizes code generation by avoiding the allocation of host memory for the resource. The resource must have read and write access functions and must not be referenced in LISA+ code. If this attribute is set to true, no variable is generated for this parameter. The read and write functions are responsible for providing and storing the value. The parameter is virtual because it is modeled through the read and write functions. |
write_function | string | none | Name of the debug write access behavior. |
The array size can be specified using:
pure integer values
Suffixes for Kilo, Mega, Giga, Tera, or Peta, for
example, 1K, 1M, 1G, 1T, or 1P relative to the mau_size.
These suffixes indicate multipliers of 210,
220, 230,
240, and 250.
expressions, for example 2k-1.
Example 2.7. Resources definition
resources
{
MEMORY { mau_size(8) } progmem[64k];
MEMORY { mau_size(32) } datamem[128k-100];
}
Memory resources can be accessed using C-array like syntax as shown in Example 2.9:
Example 2.8. C array memory accesses
behavior load(uint32_t address, uint8_t &data)
{
data = dmem[address];
}
behavior store(uint32_t address, uint8_t data)
{
dmem[address] = data;
}
The size of the memory access is always one Minimal
Addressable Unit (MAU). A 32-bit unsigned integer, for
example, is the access size for a memory with a mau_size of 32.
The access functions listed in Example 2.9 can also be used to access memory:
Example 2.9. Read and write accesses
resource.read8( uint32_t address, uint8_t & destination ); resource.read16( uint32_t address, uint16_t & destination ); resource.read32( uint32_t address, uint32_t & destination ); resource.read64( uint32_t address, uint64_t & destination ); resource.write8( uint32_t address, uint8_t source ); resource.write16( uint32_t address, uint16_t source ); resource.write32( uint32_t address, uint32_t source ); resource.write64( uint32_t address, uint64_t source );
These access functions can be used to read or write 8, 16,
32 and 64-bit quantities from or to memory. The size of the access
is implied by the function name. Only functions with a bitwidth
greater than or equal to the mau_size of the
memory can be used on a memory. If the bitwidth of the access is
greater than the mau_size the result depends
on the endianness of the memory. See Example 2.10.
Example 2.10. Mixed bitwidth accesses
behavior load(uint32_t address, uint8_t &data)
{
dmem.read8(address, data);
}
behavior store(uint32_t address, uint8_t data)
{
dmem.write8(address, data);
}
The access functions for memory are similar to the access functions for registers. You can control the way in which a memory resource is accessed by the debugger by defining your own debugger access functions. A maximum of one read-access function and one write-access function can be specified in the resources section.
Access functions are implemented as LISA+ behaviors in the
same component that holds the memory resource. They are designated
as access functions by the read_function and write_function resource
parameters. Refer to the CADIMemRead and CADIMemWrite function
descriptions for more information. See the Model Debugger
for Fast Models User Guide.
resources
{
MEMORY { mau_size(8), read_function(my_read) } progmem[64];
MEMORY { mau_size(32), write_function(my_write) } datamem[64];
}
The access functions must conform to the following prototypes:
behavior read_function_name (uint32_t space_id,
uint32_t block_id,
uint64_t offset,
uint32_t size_in_maus,
uint64_t *data,
bool side_effects,
sg::MemoryAccessContext *mac) : AccessFuncResult
behavior write_function_name (uint32_t space_id,
uint32_t block_id,
uint64_t offset,
uint32_t size_in_maus,
const uint64_t *data,
bool side_effects,
sg::MemoryAccessContext *mac) : AccessFuncResult
where:
space_idis an integer value that is a unique identifier for a memory space.
block_idis an integer value that, for the specified memory space, is a unique identifier for a memory block.
offsetis an absolute numerical offset into the space and block denoted
by the space_id and block_id parameters.
It designates the starting address for the memory access.
size_in_mausis the size of the access relative to the size of the MAU. A memory access might involve reading or writing multiple MAU quantities.
datais
the buffer from which data is read or to which data is written.
Its type is a pointer to a 64-bit unsigned integer. This size is
equal to the largest MAU size currently supported and effectively
eliminates endianness concerns. In the implementation, data is
actually an array of size_in_maus size. Write
functions protect this array by declaring the data pointer const.
side_effectsis a parameter that indicates whether the side effects for the access must be enforced. The use of this parameter with memory reads and writes is completely analogous to its use with registers. See Debugger register access functions.
MemoryAccessContextis a pointer to a MemoryAccessContext object.
This provides extensibility to the prototype and the MemoryAccessContext
class can be enriched if required. There are currently the following
interfaces:
GetAccessSizeInMaus()returns how many MAUs of memory area have to be read/written
GetMauInBytes()returns the size of a MAU, measured in bytes
GetMauInBits()returns the size of a MAU, measured in bits
The reason for accessing these values though MemoryAccessContext rather than
by coding them as constants is to lower the maintenance hazard that would
arise if a memory attribute changes.
Example 2.11 shows an example of access functions:
Example 2.11. Read and write access functions
behavior my_read(uint32_t space_id,
uint32_t block_id,
uint64_t offset,
uint32_t size_in_maus,
uint64_t *data,
bool side_effects,
MemoryAccessContext *mac) : AccessFuncResult
{
*data = progmem[offset];
return ACCESS_FUNC_OK;
}
behavior my_write(uint32_t space_id,
uint32_t block_id,
uint64_t offset,
uint32_t size_in_maus,
const uint64_t *data,
bool side_effects,
MemoryAccessContext *mac) : AccessFuncResult
{
datamem[offset] = (uint32_t) *data;
return ACCESS_FUNC_OK;
}
In Example 2.12,
two memory resources, m1 and m2,
are declared and a read access function, my_read,
is provided for them. It is possible for multiple memory spaces
and blocks to share an access function because the distinction between
them can be made at runtime by means of the space_id and block_id parameters.
For Example 2.12, this
is accomplished with a simple if / else sequence.
After determining the resource to be accessed, data is copied
into the data buffer. The for loop runs for size_in_maus times,
copying one MAU quantity on each iteration and checking whether
the accesses are within bounds or not.
Example 2.12. Implementation of a read access function
resources
{
MEMORY { space_id(1), mau_size(8), read_function(my_read) } m1[64];
MEMORY { space_id(2), mau_size(32), read_function(my_read) } m2[64];
}
behavior my_read(uint32_t space_id,
uint32_t block_id,
uint64_t offset,
uint32_t size_in_maus,
uint64_t *data,
bool side_effects,
MemoryAccessContext *mac) : AccessFuncResult
{
if (space_id == 1)
{
for (int i = 0; (i < size_in_maus) && (offset + i < 64); ++i)
data[i] = m1[offset + i];
}
else if (space_id == 2)
{
for (int i = 0; i < (size_in_maus) && (offset + i < 64); ++i)
data[i] = m2[offset + i];
}
else
return ACCESS_FUNC_IllegalArgument;
return ACCESS_FUNC_OK;
}
If you set the virtual resource parameter
to true, you prevent memory from being allocated
at run time. A virtual memory resource must provide debug read and
write functions and cannot be directly accessed from LISA+ source
code. If you do not define valid read and write access functions,
or attempt to access the resource through LISA+ code, a build failure
occurs.