IV Creating Virtual Systems 26 Components
Model Builder User’s Guide  /  IV Creating Virtual Systems  / 

25 Memory Spaces

This chapter shows you how to use the memory spaces in Simics. Memory spaces is a fundamental abstraction in Simics providing support for generic 64-bit address spaces into which memory and devices can be mapped. More concretely a memory space takes a stream of transactions to an address space and distributes them to devices mapped into the address space in a highly efficient manner while optionally providing address translations, byte swapping, and break point support. Memory space objects can be cascaded to form arbitrarily complex mappings and support dynamic reconfiguration and remapping at run time through attributes to support modeling of buses with dynamic addressing.

25.1 Memory Space Basics

Simics memory-spaces are handled by the generic memory-space class. A memory-space object implements interface functions for memory accesses, and it has attributes specifying how the mappings are set up.

The most important attribute in a memory-space is the map attribute. This is a list of mapped objects that may contain devices, RAM and ROM objects, and other memory-spaces. In addition to the map attribute, there is also a default_target attribute that is used for accesses that do not match any of the targets in the map list.

Python example of a memory-space object where already created objects are mapped into a new memory space:

@mem = pre_conf_object('phys_mem', 'memory-space')
@mem.map = [[0x00000000, conf.ram0,    0, 0,          0xa0000],
            [0x000a0000, conf.vga0,    1, 0,          0x20000],
            [0x000c0000, conf.rom0,    0, 0,          0x10000],
            [0x000f0000, conf.rom0,    0, 0,          0x10000],
            [0x00100000, conf.ram0,    0, 0x100000, 0xff00000],
            [0xfee00000, conf.apic0,   0, 0,           0x4000],
            [0xffe81000, conf.hfs0,    0, 0,               16],
            [0xffff0000, conf.rom0,    0, 0,          0x10000]]
@mem.default_target = [conf.pci_mem0, 0, 0, conf.pci_mem0]
@SIM_add_configuration([mem], None)

The fields for an entry in the map list are as follows:

base
The start address of the mapping in the memory space.
object
Reference to the mapped object or port. In the case of an object mapping this is just the object and in the case of a port mapping it is a two element list: [object, port name]. One common example for the use of port mappings is mapping banks of DML devices.
function
An object specific identification number for this mapping. The function number is typically only used by older device models with several mappings. When such a device is accessed, the function number can be used to figure out what mapping it was accessed through. Newer device models use port mappings instead. If a port mapping is used the function number is not passed on to the target device. The function number is part of the map_info_t struct, which is passed as a parameter of all io_memory interface functions.
offset
The start offset in the target object. This is often used when a memory-space is mapped in another memory-space. Example: memory-space B is mapped in space A at base 0x4000 with length 0x1000, and with offset 0x2000. If an access is made in space A at address 0x4010, it will be forwarded to space B at address 0x2010. Without any offset in the mapping, the resulting address would have been 0x10.
length
The size of the mapping in bytes.
target
(optional) If object is not the final destination for the access, then target is a reference to the actual target object or port. It has the same format as object. This is described in more details in the section about different mapping types.
priority
(optional) The priority of the mapping. The highest priority is -32768, and the lowest is 32767; the default is 0. If mappings overlap, then the priority field specifies what mapping that has precedence. It is an error if overlapping mappings have the same priority. Usually overlapping mappings should be avoided, but for bridges that catch unclaimed accesses in specific address ranges the priority field is useful. There are also devices that have overlapping mappings that have different priorities, and in that case the priority field in the map list can be used.
align-size
(optional) The align-size can be used if a target does not support large accesses. Accesses that crosses an alignment boundary will be split into several transactions by the Simics memory system. By default this will be set to 4 bytes for port-space devices and 8 bytes for other devices, but it is not used for memory. NOTE: The align_size based splitting of transactions only applies to targets implementing the generic_transaction_t based interfaces port_space, io_memory, translate, and bridge.
byte-swap
(optional) Some device mappings swap the data bytes in a transaction, to support mixed-endian environments. Mappings with an align-size of 2, 4, or 8 may set the byte-swap field to one of 0 to 3 where 0 is none, 1 is bus, 2 is bus-trans and 3 is trans. As the name suggests, none performs no swapping while bus swaps data based on the align-size setting. If any swapping is used, bus is most common. It is also possible to swap all bytes of the access based on the access size by using trans and finally combine the two swappings into bus-trans. As an example, consider a mapping with a 4-byte align-size and memory at address 0 that contains the following bytes: 0x00 0x01 0x02 0x03. A 2-byte big-endian read access at address 0 will give the following values as results. No swap: 0x0001, bus swap: 0x0302, bus and transaction swap: 0x0203 and transaction swap: 0x0100.

25.2 Memory Space Commands

All mappings in a memory-space can be viewed with the <memory-space>.map command. Example:

simics> board.mb.nb.pci_mem.map
       Base Object                  Fn Offset   Length Target              Prio Align Swap
    0xa0000 board.mb.gpu.dmap_space       0x0  0x20000                        0
    0xc0000 board.mb.shadow               0x0  0x40000 board.mb.shadow_mem    1
 0xfec00000 board.mb.sb.ioapic            0x0     0x20                        0     8
 0xffe00000 board.mb.rom                  0x0 0x200000                        0
  -default- board.mb.dram_space           0x0

Another useful command is devs, that lists all mapped devices in the system.

simics> devs
 Count    Device        Space            Range                                   Func/Port
       0  chmmu0        phys_io0         0x0000040000400000 - 0x0000040000400047    0
       0  e2bus24B_1    bus_pcicfg24B    0x0000000000000800 - 0x00000000000008ff  255
       0  empty0_0      phys_io0         0x000007fff0800060 - 0x000007fff080006f    0
       0  empty1_0      phys_io0         0x000007fff091e000 - 0x000007fff091e11f    0
       0  fpost_data0   phys_io0         0x000007fff0104000 - 0x000007fff0105fff    0
       0  glm0          bus_pcicfg25B    0x0000000000001000 - 0x00000000000010ff  255
[…]

It is also possible to modify mappings interactively from the command line, or from a script, by using the add-map and del-map memory-space commands. Try help <memory-space>.add-map from the command line for more information or refer to the API Reference Manual.

Additionally memory mappings can be viewed in the GUI see Getting Started or the Simics User’s Guide for details.

25.3 Memory Mapping Use Cases

There are a few different kinds of memory mappings. All use the format described in the previous section.

Device Mapping
The most common kind of mapping. It is used for devices, RAM and ROM objects. The target field is not set. For devices this is often a port mapping.
Translator Mapping
Sometimes the address has to be modified between memory-spaces, or the destination memory-space depends on the address or some other aspect of the access. In these cases a translator can be used. A translator mapping is specified with the translator in the object field, and the default target as target. The translator has to implement either the translator or the translate interface. When an access reaches a translator mapping, the translate function in the interface is called. Please refer to the documentation of the translator and the translate interfaces for more information about their usage.
Translate to RAM/ROM Mapping
Used to map RAM and ROM objects with a translator first. The object field is set to the translator, and target is set to the RAM/ROM object.
Space-to-space Mapping
Map one memory-space in another. The object field is set to the destination memory-space object.
Bridge Mapping
A bridge mapping is typically used for mappings that are set up by some kind of bridge device. The purpose of a bridge mapping is to handle accesses where nothing is mapped, in a way that corresponds to the bus architecture. For a bridge mapping, the object field is set to the bridge device, implementing the bridge interface. The target field is set to the destination memory-space. If both a translator and a bridge are needed, they must be implemented by the same object. If an access is made where nothing is mapped, the memory-space by default returns the Sim_PE_IO_Not_Taken pseudo exception. But if the access was made through a bridge mapping, the bridge device will be called to notify it about the unmapped access. It can then update any internal status registers, specify a new return exception, and set the data that should be returned in the case of a read access. Since the bridge is associated with the mapping and not the memory-space itself, several bridges can exist for one space, and devices doing accesses directly to the memory-space in question will not affect the bridge for non-mapped addresses. In the latter case, the device itself has to interpret the Sim_PE_IO_Not_Taken exception. The Sim_PE_IO_Error exception, indicating that a device returned an error is also sent to the bridge. Finally, bridges are called for accesses that generate Sim_PE_Inquiry_Outside_Memory, i.e., an inquiry access where nothing is mapped. In this case the bridge may have to set a default return value, such as -1.

25.4 Avoiding Circular Mappings

Since memory-spaces can be mapped in other memory-spaces, it is possible to create loops where accesses never reach any target device. One typical case is a PCI memory-space with bridges that has both downstream and upstream mappings. In a real system, the bridge typically does not snoop its own transactions and there will be no loop. In Simics there are usually no bridge devices mapped between different memory-spaces, instead the bridge will create space-to-space mappings. The bridge has to be careful to avoid addresses which will cause loops between memory-spaces when accessed.

To catch invalid configurations Simics will make sure that an access does not loop by terminating it after 512 memory-space transitions. If this limit is reached, it is considered a configuration error and Simics will stop.

IV Creating Virtual Systems 26 Components