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.
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:
map_info_t struct, which is passed as a parameter of all
io_memory interface functions.align_size based splitting of transactions only applies to targets
implementing the generic_transaction_t based interfaces port_space,
io_memory, translate, and bridge.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.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.
There are a few different kinds of memory mappings. All use the format described in the previous section.
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.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.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.