One of the important reasons to use a simulator such as Simics is the ability to inspect hardware in a non-intrusive way. This section will describe various Simics features that facilitates hardware inspection.
Here are some examples of how to inspect processors and devices, when running the
%simics%/targets/qsp-x86/firststeps.simics
target machine.
$ bin/simics targets/qsp-x86/firststeps.simics
list-objects
command.simics> list-objects -local
┌─────────────────┬───────────────────┐
│ Object │ Component Class │
├─────────────────┼───────────────────┤
│board │<chassis_qsp_x86> │
│ethernet_switch0 │<ethernet_switch> │
│service_node_cmp0│<service_node_comp>│
└─────────────────┴───────────────────┘
┌───────────────────┬─────────────────┐
│ Object │ Class │
├───────────────────┼─────────────────┤
│bp │<bp-manager> │
│breakpoints │<breakpoints-old>│
│default_sync_domain│<sync_domain> │
│params │<script-params> │
│prefs │<preferences> │
│sim │<sim> │
└───────────────────┴─────────────────┘
sim
object, we have the network related objects, and at the top we have the actual machine. We can look at the objects inside it:simics> list-objects namespace = board -local
┌─────────────────┬───────────────────────┐
│ Object │ Component Class │
├─────────────────┼───────────────────────┤
│board.cdrom │<sata_cdrom_comp> │
│board.console │<gfx_console_comp> │
│board.disk0 │<sata_disk_comp> │
│board.disk1 │<sata_disk_comp> │
│board.mb │<motherboard_x58_ich10>│
│board.serconsole │<txt_console_comp> │
│board.serconsole1│<txt_console_comp> │
│board.tablet │<usb_tablet_component> │
└─────────────────┴───────────────────────┘
┌──────────────────┬──────────────┐
│ Object │ Class │
├──────────────────┼──────────────┤
│board.cell │<cell> │
│board.cell_context│<context> │
│board.cell_rec0 │<recorder> │
│board.software │<os_awareness>│
└──────────────────┴──────────────┘
list-objects
command. The -tree
option displays the objects in a hierarchical fashion.simics> list-objects -show-port-objects namespace = board.mb.cpu0 -tree
┐
├ apic[0] ┐
│ └ [0] ┐
│ ├ bank ┐
│ │ └ apic_regs
│ └ port ┐
│ └ freq_listener
├ core[0] ┐
│ └ [0] ┐
│ └ vtime ┐
│ ├ cycles
│ └ ps
├ mem[0] ┐
│ └ [0]
├ socket
└ tlb[0] ┐
└ [0]
list-processors
command.
Note the *
to the right of board.mb.cpu0.core[0][0]
and the last line * = selected CPU
.
In this system, there is only one processor, but in systems with multiple processors,
the commands pselect
and cpu
can be used to set and change the current processor.
More on this here.simics> list-processors
┌────────────────────────┬─┬─────────┬────────┬────────────────────────────────────────┐
│ CPU Name │ │CPU Class│ Freq │ Disassembly │
├────────────────────────┼─┼─────────┼────────┼────────────────────────────────────────┤
│board.mb.cpu0.core[0][0]│*│x86QSP1 │2.00 GHz│cs:0x000000000000fff0 p:0x0fffffff0 nop│
└────────────────────────┴─┴─────────┴────────┴────────────────────────────────────────┘
* = selected CPU
list-processors
command can show information about the state of each processor core, to help diagnose the current state of the system. There are multiple switches available, use help or tab-completion to see the available options. The -disassemble
option is particularly interesting, as it often indicates processor modes like wait states.simics> list-processors -disassemble
┌────────────────────────┬─┬─────────┬────────┬────────────────────────────────────────┐
│ CPU Name │ │CPU Class│ Freq │ Disassembly │
├────────────────────────┼─┼─────────┼────────┼────────────────────────────────────────┤
│board.mb.cpu0.core[0][0]│*│x86QSP1 │2.00 GHz│cs:0x000000000000fff0 p:0x0fffffff0 nop│
└────────────────────────┴─┴─────────┴────────┴────────────────────────────────────────┘
The current processor (marked with a *
in list-processors
)
is used by some global commands, for example in print-processor-registers,
as the processor the command operates to.
To access the current processor, use the cpu
object alias.
The cpu
object alias can be used both to get the current processor, and
to tab-expand commands, child objects and attributes of the current processor.
simics> cpu
"board.mb.cpu0.core[0][0]"
simics> cpu # press tab twice to expand everything starting with cpu
cpu-> cpu-pages-dump cpu-switch-time cpu. cpu.vtime.
simics> cpu. # press tab twice to expand child objects and commands
cpu.aprof-views cpu.break-vmread cpu.print-idt
cpu.bp-break-control-register cpu.break-vmwrite cpu.print-mp-tables
...
simics> cpu-> # press tab twice to expand attributes
cpu->a20_inhibited cpu->ia32_unknown_3fe
cpu->a20mask cpu->ia32_unknown_4b
...
pselect
. Without argument this shows
the current processor, just like cpu
.simics> pselect "board.mb.cpu0.core[0][0]"
simics> pselect
"board.mb.cpu0.core[0][0]"
print-processor-registers
command.simics> board.mb.cpu0.core[0][0].print-processor-registers
16-bit legacy real mode
rax = 0x0000000000000000 r8 = 0x0000000000000000
rcx = 0x0000000000000000 r9 = 0x0000000000000000
rdx = 0x00000000000106a1 r10 = 0x0000000000000000
rbx = 0x0000000000000000 r11 = 0x0000000000000000
rsp = 0x0000000000000000 r12 = 0x0000000000000000
rbp = 0x0000000000000000 r13 = 0x0000000000000000
rsi = 0x0000000000000000 r14 = 0x0000000000000000
rdi = 0x0000000000000000 r15 = 0x0000000000000000
rip = 0x000000000000fff0
eflags = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 = 0x00000002
I V V A V R - N I I O D I T S Z - A - P - C
D I I C M F T O O F F F F F F F F F
P F P P
L L
print-processor-registers
.simics> print-processor-registers
output-radix
command that specifies the base when numbers are displayed.simics> output-radix 16
simics> %rdx
0x106a1
print-device-regs
command. For example, we can look at the DMI device. First, we locate it in the system.simics> list-classes -l substr = dmi -show-port-classes
The following classes have been registered:
┌───────────────────┬──────────────────────────────────────────────────┐
│ Class │ Short description │
├───────────────────┼──────────────────────────────────────────────────┤
│osa_admin_emulator │deprecated OS awareness administrator │
│x58-dmi │Intel® X58 DMI unit │
│x58-dmi.HRESET │ │
│x58-dmi.io_regs │ │
│x58-dmi.msg │legacy PCI INTx message to pci_interrupt converter│
│x58-dmi.pcie_config│ │
│x58-dmi.phy │ │
└───────────────────┴──────────────────────────────────────────────────┘
simics> list-objects class = x58-dmi -all
┌──────────────────┬─────────┐
│ Object │ Class │
├──────────────────┼─────────┤
│board.mb.nb.bridge│<x58-dmi>│
└──────────────────┴─────────┘
simics> print-device-regs bank = board.mb.nb.bridge
Bank: io_regs
Offset Name Size Value | Offset Name Size Value
------------------------------------+---------------------------------
0xcf8 config_address 4 0x0 | 0xcfc config_data 4 0x0
Bank: pcie_config
Offset Name Size Value
------------------------------------------
0x0 vendor_id 2 0x8086
0x2 device_id 2 0x3400
0x4 command 2 0x0
0x6 status 2 0x10
0x8 revision_id 1 0x13
0x9 class_code 3 0x80000
0xc cache_line_size 1 0x0
0xd latency_timer 1 0x0
0xe header_type 1 0x0
0xf bist 1 0x0
0x2c subsystem_vendor_id 2 0x8086
0x2e subsystem_id 2 0x0
0x34 capabilities_ptr 1 0x0
0x3c interrupt_line 1 0x0
0x3d interrupt_pin 1 0x0
simics> print-device-regs bank = board.mb.nb.bridge pattern = vendor_id
Bank: pcie_config
Offset Name Size Value
-------------------------------
0x0 vendor_id 2 0x8086
print-device-reg-info
command.simics> print-device-reg-info register = board.mb.nb.bridge.bank.pcie_config.vendor_id
Vendor ID [board.mb.nb.bridge.bank.pcie_config.vendor_id]
Bits : 16
Offset : 0x0
Value : 32902 (0x8086)
Bit Fields:
vendor_id @ [15:0] : 1000000010000110
When retrieving a register value for inspection or use in further code, it is better to use one of the commands designed for that purpose:
get-device-reg
get-device-offset
read-device-reg
read-device-offset
set-device-reg
set-device-offset
write-device-reg
write-device-offset
The command names have the following meanings:
Operation type:
Target specification:
simics> get-device-reg board.mb.nb.bridge.bank.pcie_config.device_id
0x3400
simics> get-device-offset board.mb.nb.bridge.bank.pcie_config offset = 2 size = 2
0x3400 (LE)
To sum up, we have shown a few simple ways in which the hardware can be inspected. One important point is that the inspection is non-intrusive, any software running on the target machine cannot notice anything of our inspection.
Simics hardware models generally output log messages for various kinds of events. The Simics log system offers a very powerful system for configuring which log messages to see - from which objects, at which level. The result is often large volumes of output. That output can be configured and sent to files for later inspection, as well as used in scripts to stop Simics or take other actions when a log message appears.
Here we will show some logging examples when running the
%simics%/targets/qsp-x86/firststeps.simics
target machine.
$ bin/simics targets/qsp-x86/firststeps.simics
log-setup
command. To check the current settings, just issue log-setup
alone:simics> log-setup
Time stamp : disabled
Picoseconds : disabled
Real time : disabled
Disassemble : disabled
Log to console : enabled
Include group : disabled
Include level : disabled
Log file : disabled
log-level
object command. This will show or configure the log level for the object.simics> log-level board.mb.nb.bridge 2
[board.mb.nb.bridge] Changing log level: 1 -> 2
simics> log-level board.mb.nb.bridge
Current log levels:
Lvl Object | Lvl Object
-----------------------------------------+------------------------------------
2 board.mb.nb.bridge | 2 board.mb.nb.bridge.port
2 board.mb.nb.bridge.bank | 2 board.mb.nb.bridge.port.HRESET
2 board.mb.nb.bridge.bank.io_regs | 2 board.mb.nb.bridge.port.msg
2 board.mb.nb.bridge.bank.pcie_config | 2 board.mb.nb.bridge.port.phy
The log messages that are displayed are those which have a level less than or equal to the ones configured on the object.
Each log message also has a log type, and similarly like log levels, we can configure which log types to display on each object:
simics> log-type board.mb.nb.bridge info
board.mb.nb.bridge:
enabled log types: "info"
disabled log types: "error" "spec-viol" "unimpl" "critical"
board.mb.nb.bridge.bank:
enabled log types: "info"
disabled log types: "error" "spec-viol" "unimpl" "critical"
board.mb.nb.bridge.bank.io_regs:
enabled log types: "info"
disabled log types: "error" "spec-viol" "unimpl" "critical"
board.mb.nb.bridge.bank.pcie_config:
enabled log types: "info"
disabled log types: "error" "spec-viol" "unimpl" "critical"
board.mb.nb.bridge.port:
enabled log types: "info"
disabled log types: "error" "spec-viol" "unimpl" "critical"
board.mb.nb.bridge.port.HRESET:
enabled log types: "info"
disabled log types: "error" "spec-viol" "unimpl" "critical"
simics> run 1000
[board.mb.nb.bridge.bank.io_regs info] PCIe write 0xe0000001 to ff:0.1 offset 0x50, 4 bytes
It is also possible to set breakpoints on log messages. These can similarly be filtered on object, log type etc.
To see when in virtual time a log message is printed, use log-setup -time-stamp
. This will print the processor that provided the virtual time for the message, its current instruction pointer or program counter (address of the instruction active when the log was printed), and its current cycle count. To turn it off, use -no-time-stamp
. The -pico-seconds
and -real-time
are similar, but prints picosecond resolution timestamps and real time, respectively.
simics> log-setup -time-stamp
simics> bp.log.break object = board.mb.nb.bridge.bank.io_regs type = info
Breakpoint 2: Break on 'info' log messages from board.mb.nb.bridge.bank.io_regs hierarchy
simics> run
[board.mb.nb.bridge.bank.io_regs info] {board.mb.cpu0.core[0][0] 0xfffecbf7 136713}
PCI read 0x0 from bus 0, device 31, function 0, register 68 (0x44, 1 bytes), PCIE address = 0xf8044
[board.mb.nb.bridge.bank.io_regs] Breakpoint 1: board.mb.nb.bridge.bank.io_regs log message of type info
To send all log outputs to a file, use log-setup logfile=<filename>
. To overwrite an existing file, the -overwrite
flag must be given. To stop output, use the command log-setup -no-log-file
.
Tracing is a way to observe what is going on during the simulation. Simics has a Breakpoint Manager that includes functionality for tracing various types of events. This means that messages (in fact, Simics log messages) are printed when an event of the specified occurs. Such a sequence of messages is what is here is known as a trace.
Here we will show some tracing examples when running the
%simics%/targets/qsp-x86/firststeps.simics
target machine.
$ bin/simics targets/qsp-x86/firststeps.simics
simics> bp.control_register.trace -all
[board.mb.cpu0.core[0][0] info] VMP not engaged. Reason: hap installed on CR0 read.
2
simics> run 1000
[bp.control_register trace] [trace:2] board.mb.cpu0.core[0][0] cr0 <- 0x40000023
[bp.control_register trace] [trace:2] board.mb.cpu0.core[0][0] cr4 <- 0x640
[bp.control_register trace] [trace:2] board.mb.cpu0.core[0][0] read of cr4
[bp.control_register trace] [trace:2] board.mb.cpu0.core[0][0] cr4 <- 0x640
log-setup
command. For example, each message can be prepended with a time-stamp, indicating the processor, program counter and the cycle count at the point where the event occurred.simics> log-setup -time-stamp
simics> c 17450
[bp.control_register trace] {board.mb.cpu0.core[0][0] 0xfffec638 398442} [trace:2] board.mb.cpu0.core[0][0] read of IA32_APIC_BASE
simics> bp.delete -all
simics> bp.memory.trace address = 0 length = 100000 -r
simics> run 365_016_915 cycles
[bp.memory trace] {board.mb.cpu0.core[0][0] 0x836872 365415364} [trace:3]
board.cell_context 'r' access to v:0x10 len=4
Several other types of events can also be traced, such as target console string output and hits at specific source code lines.
The Simics instrumentation framework has powerful ways to inspect the simulation. It is built on four core concepts:
At the Simics command line, it is the tools and filters that are manipulated. To see a list of available tools:
simics> list-instrumentation-tools substr = bank
┌──────────────────────┬──────────────────┬──────────────────────────────┐
│ Tool create command │ Tool class │ Description │
├──────────────────────┼──────────────────┼──────────────────────────────┤
│new-bank-coverage-tool│bank_coverage_tool│register bank coverage tool │
│new-bank-patch-tool │bank_patch_tool │device access miss repair tool│
└──────────────────────┴──────────────────┴──────────────────────────────┘
Here is an example of using instrumentation to compare user and supervisor mode instruction occurrences, when running the
%simics%/targets/qsp-x86/firststeps.simics
target machine.
$ bin/simics targets/qsp-x86/firststeps.simics
Boot the target machine.
Create two histogram tools and connect them to all processors.
simics> new-instruction-histogram name = user_instr -connect-all
[board.mb.cpu0.core[0][0] info] VMP not engaged. Reason: instrumentation enabled.
Created user_instr (connected to 1 processor)
simics> new-instruction-histogram name = kernel_instr -connect-all
Created kernel_instr (connected to 1 processor)
simics> new-cpu-mode-filter name = usermode mode = user
Created filter usermode with mode user
simics> new-cpu-mode-filter name = kernelmode mode = supervisor
Created filter kernelmode with mode supervisor
simics> user_instr.add-filter filter = usermode
Added filter to 1 connections
simics> kernel_instr.add-filter filter = kernelmode
Added filter to 1 connections
simics> run 4 s
simics> user_instr.histogram max = 15
┌─────────┬────────┬────────┬───────┬───────────┐
│ Row # │mnemonic│ Count │Count% │Accumulated│
│ │ │ │ │ Count% │
├─────────┼────────┼────────┼───────┼───────────┤
│ 1│mov │12137948│ 28.98%│ 28.98%│
│ 2│cmp │ 3030796│ 7.24%│ 36.22%│
│ 3│je │ 2846035│ 6.80%│ 43.01%│
│ 4│test │ 2661377│ 6.35%│ 49.37%│
│ 5│push │ 2068299│ 4.94%│ 54.30%│
│ 6│pop │ 2022557│ 4.83%│ 59.13%│
│ 7│jne │ 1810666│ 4.32%│ 63.46%│
│ 8│add │ 1596786│ 3.81%│ 67.27%│
│ 9│xor │ 1540722│ 3.68%│ 70.95%│
│ 10│lea │ 1492439│ 3.56%│ 74.51%│
│ 11│jmp │ 1056509│ 2.52%│ 77.03%│
│ 12│sub │ 914262│ 2.18%│ 79.22%│
│ 13│ret │ 874834│ 2.09%│ 81.30%│
│ 14│call │ 874753│ 2.09%│ 83.39%│
│ 15│movzx │ 858974│ 2.05%│ 85.44%│
├─────────┼────────┼────────┼───────┼───────────┤
│# 15/149 │ │ │ │ │
│Sum (all)│ │41883708│100.00%│ │
│Sum shown│ │35786957│ 85.44%│ │
└─────────┴────────┴────────┴───────┴───────────┘
simics> kernel_instr.histogram max = 15
┌─────────┬────────┬────────┬───────┬───────────┐
│ Row # │mnemonic│ Count │Count% │Accumulated│
│ │ │ │ │ Count% │
├─────────┼────────┼────────┼───────┼───────────┤
│ 1│mov │ 8427494│ 37.31%│ 37.31%│
│ 2│je │ 1372749│ 6.08%│ 43.39%│
│ 3│push │ 1362419│ 6.03%│ 49.42%│
│ 4│test │ 1326411│ 5.87%│ 55.29%│
│ 5│pop │ 1315206│ 5.82%│ 61.12%│
│ 6│cmp │ 1227033│ 5.43%│ 66.55%│
│ 7│xor │ 910401│ 4.03%│ 70.58%│
│ 8│jne │ 868442│ 3.84%│ 74.42%│
│ 9│add │ 723691│ 3.20%│ 77.63%│
│ 10│lea │ 695604│ 3.08%│ 80.71%│
│ 11│call │ 616243│ 2.73%│ 83.44%│
│ 12│ret │ 597695│ 2.65%│ 86.08%│
│ 13│and │ 534859│ 2.37%│ 88.45%│
│ 14│sub │ 358369│ 1.59%│ 90.04%│
│ 15│jmp │ 268310│ 1.19%│ 91.23%│
├─────────┼────────┼────────┼───────┼───────────┤
│# 15/108 │ │ │ │ │
│Sum (all)│ │22586736│100.00%│ │
│Sum shown│ │20604926│ 91.23%│ │
└─────────┴────────┴────────┴───────┴───────────┘
Here is another example of using instrumentation to show exception occurrences, when running the
%simics%/targets/qsp-x86/firststeps.simics
target machine.
$ bin/simics targets/qsp-x86/firststeps.simics
simics> new-exception-histogram name = exc_hist -connect-all
[board.mb.cpu0.core[0][0] info] VMP not engaged. Reason: instrumentation enabled.
Created exc_hist (connected to 1 processor)
simics> run 60 s
simics> exc_hist.histogram
┌─────┬────────────────────────────┬─────┬───────┬───────────┐
│Row #│ Exception │Count│Count% │Accumulated│
│ │ │ │ │ Count% │
├─────┼────────────────────────────┼─────┼───────┼───────────┤
│ 1│Page_Fault_Exception │ 7956│ 44.22%│ 44.22%│
│ 2│Interrupt_64 │ 5312│ 29.52%│ 73.74%│
│ 3│Interrupt_34 │ 2720│ 15.12%│ 88.86%│
│ 4│Interrupt_35 │ 1535│ 8.53%│ 97.39%│
│ 5│Interrupt_236 │ 314│ 1.75%│ 99.14%│
│ 6│Interrupt_48 │ 112│ 0.62%│ 99.76%│
│ 7│General_Protection_Exception│ 21│ 0.12%│ 99.88%│
│ 8│Interrupt_37 │ 16│ 0.09%│ 99.97%│
│ 9│NMI │ 4│ 0.02%│ 99.99%│
│ 10│Interrupt_40 │ 1│ 0.01%│ 99.99%│
│ 11│Interrupt_39 │ 1│ 0.01%│ 100.00%│
├─────┼────────────────────────────┼─────┼───────┼───────────┤
│Sum │ │17992│100.00%│ │
└─────┴────────────────────────────┴─────┴───────┴───────────┘
Source code for instrumentation tools are in
src/extensions/instruction-histogram
src/extensions/exception-histogram
src/extensions/cpu-mode-filter
in the Simics-Base package.
Let us now show a simple example of how to use simple cache model in Simics. By default, Simics does not model any cache system. It uses its own memory system to achieve high speed simulation and modeling a hardware cache model would only slow it down. However, via the instrumentation framework, the flow of memory operations coming from the processor can be captured, and this allows modelling caches.
Here is an example of using instrumentation to connect a simple cache model, when running the
%simics%/targets/qsp-x86/firststeps.simics
target machine.
$ bin/simics targets/qsp-x86/firststeps.simics
simics> new-simple-cache-tool name = cachetool -connect-all
[board.mb.cpu0.core[0][0] info] VMP not engaged. Reason: instrumentation enabled.
Created cachetool (connected to 1 provider)
simics> cachetool.add-l1d-cache name = l1d line-size = 64 sets = 64 ways = 12 -ip-read-prefetcher prefetch-additional = 1
Created cache board.mb.cpu0.cache[0].l1d
simics> cachetool.add-l1i-cache name = l1i line-size = 64 sets = 64 ways = 8
Created cache board.mb.cpu0.cache[0].l1i
simics> cachetool.add-l2-cache name = l2 line-size = 64 sets = 1024 ways = 20 -prefetch-adjacent prefetch-additional = 4
Created cache board.mb.cpu0.cache[0].l2
simics> cachetool.add-l3-cache name = l3 line-size = 64 sets = 8192 ways = 12
Created cache board.mb.cpu0.l3
simics> run 55 s
simics> board.mb.cpu0.cache[0].l1d.print-statistics
┌─────┬───────────────────────────────────┬─────────┬─────┐
│Row #│ Counter │ Value │ % │
├─────┼───────────────────────────────────┼─────────┼─────┤
│ 1│read accesses │699427620│ │
│ 2│read misses │ 2905903│ 0.42│
│ 3│write accesses │432645847│ │
│ 4│write misses │ 7196304│ 1.66│
│ 5│prefetch accesses │ 6509721│ │
│ 6│prefetch misses │ 4468886│68.65│
│ 7│prefetched lines used │ 2828455│43.45│
│ 8│evicted lines (total) │ 14570325│ │
│ 9│evicted modified lines │ 7651899│52.52│
│ 10│entire cache flushes (invd, wbinvd)│ 8│ │
│ 11│uncachable read accesses │110513271│ │
│ 12│uncachable write accesses │ 70608384│ │
└─────┴───────────────────────────────────┴─────────┴─────┘
%simics%/targets/qsp-x86/qsp-client-core.simics
target system, which has a more modern processor with 4 cores, we get the following statistics:simics> board.mb.cpu0.cache[0].l1d.print-statistics
┌─────┬───────────────────────────────────┬─────────┬─────┐
│Row #│ Counter │ Value │ % │
├─────┼───────────────────────────────────┼─────────┼─────┤
│ 1│read accesses │651920234│ │
│ 2│read misses │ 2659454│ 0.41│
│ 3│write accesses │432965032│ │
│ 4│write misses │ 8850450│ 2.04│
│ 5│prefetch accesses │ 5561939│ │
│ 6│prefetch misses │ 3800816│68.34│
│ 7│prefetched lines used │ 2176319│39.13│
│ 8│prefetch instructions │ 1741│ │
│ 9│evicted lines (total) │ 15309952│ │
│ 10│evicted modified lines │ 9257461│60.47│
│ 11│entire cache flushes (invd, wbinvd)│ 8│ │
│ 12│uncachable read accesses │ 56577895│ │
│ 13│uncachable write accesses │ 39917361│ │
└─────┴───────────────────────────────────┴─────────┴─────┘
Source code for cache model is in
src/extensions/simple-cache-tool
in the Simics-Base package.