Skip to main content
Department of Information Technology

Important

You may have to give the -stall options to simics, depending on the current workload of the machine you are running on.
Without it you can experience some long error messages when starting simics (but with it simics will run slower).
host$ ./simics -stall targets/malta/malta-linux-common.simics

Simics Introduction Lab

The purpose of this lab is to get you started with Simics, and show you some of the basic debug functionality. We assume that you start by installing Simics as detailed in the installation guide.

Run Simics with Linux on a MIPS machine

Now that you're Simics installation is completed, let's take the simulator for a spin. We will do this by running a Montavista Linux on Simics/MIPS.

  • Change directory to your simics workspace:

host$ cd ~/simics-workspace

  • Start simics, using the simics script. As the argument, give the name of the startup script (.simics file) that you will use to start Simics. In our case, the startup file is called targets/malta/malta-linux-common.simics.

host$ ./simics targets/malta/malta-linux-common.simics

  • If this fails to work, please see the clarifications and FAQ page for more information.
  • When Simics starts, two windows should open on the side (one text terminal and one small window representing the LCD display of the simulated Malta board). In the main window, you will be greeted by a Simics startup message, and finally you will arrive at the Simics command prompt:

Checking out a license... done: academic license.
                              
  +----------------+    Copyright 1998-2006 by Virtutech, All Rights Reserved
  |   Virtutech    |    Version: Simics 3.0.24
  |     Simics     |    Build: 1368  Host: v9-sol8-64
  +----------------+
    www.simics.com      "Virtutech" and "Simics" are trademarks of Virtutech AB

Use of this software is subject to appropriate license.
Type 'copyright' for details on copyright.
Type 'help help' for info on the on-line documentation.

simics> 

  • Start booting Linux by typing the command c, for "continue":

simics> c

  • Now, you should be getting output in the text terminal. After a (short) while, the simulated Montavista Linux will arrive at its command-prompt:

serial_console_after_boot.png

  • You should also see a scrolling text in the LCD window:

malta_lcd.png

  • In the main Simics window you will also see a bunch of warnings about memory accesses. in the main Simics window).
  • Try som Linux commands at this prompt, such as ls, cd, pwd. Use cat to look at the contents of files. To see what the Linux thinks that it is running from, try cat /proc/cpuinfo:

sh-2.04# cat /proc/cpuinfo
cpu                     : MIPS
cpu model               : R4310 V0.0
system type             : unknown unknown
BogoMIPS                : 49.86
byteorder               : little endian
unaligned accesses      : 0
wait instruction        : no
microsecond timers      : no
extra interrupt vector  : yes
hardware watchpoint     : yes
VCED exceptions         : not available
VCEI exceptions         : not available

  • To get back to the Simics prompt, we need to stop the simulation. Bring the Simics console to the front and press ctrl-C. This should get you back to the Simics prompt. When we stop simulation in this manner, Simics will show you the instruction where execution was stopped, with both its virtual (v:) and physical address shown (p:):

[cpu0] v:0x8010870c p:0x0010870c  beq v0,zero,0x8010871c
simics>

Using the Simics command prompt

From the Simics command prompt, you have a lot of powerful commands available. Here we will walk you through the most basic information; for more commands and tips on debugging, look at the debug tips page.

  • Simics is an object-oriented environment: the entire simulated machine is built up from a number of objects, typically one for each device, processor, or memory in the system. Plus some for the basic functionality provided by Simics. All objects have commands defined for them, some more and some less. To see all objects in the current simulation, use the command list-objects:

simics> list-objects
Component Class       Object           
---------------------------------------
<malta-system>        system_cmp0      
<south-bridge-piix4>  south_bridge_cmp0
<std-super-io>        sio_cmp0         
<std-text-console>    text_console_cmp0

Class           Object          | Class           Object         
--------------------------------+--------------------------------
<DS12887>       rtc0            | <malta>         malta          
<GT64120-pci>   gt_pci_0_0      | <memory-space>  cbus_space     
<GT64120-pci>   gt_pci_0_1      | <memory-space>  pci_bus0_conf  
<GT64120-pci>   gt_pci_1_0      | <memory-space>  pci_bus0_io    
<GT64120-pci>   gt_pci_1_1      | <memory-space>  pci_bus0_mem   
<GT64120>       gt              | <memory-space>  pci_bus1_conf  
<ISA>           isa0            | <memory-space>  pci_bus1_io    
<NS16550>       com1            | <memory-space>  pci_bus1_mem   
<NS16550>       com2            | <memory-space>  phys_mem       
<apm>           apm0            | <mips-4kc>      cpu0           
<context>       primary_context | <pci-bus>       pci_bus0       
<floppy-drive>  fd0             | <pci-bus>       pci_bus1       
<floppy-drive>  fd1             | <piix4_ide>     pci_to_ide0    
<hostfs>        hfs             | <piix4_isa>     pci_to_isa0    
<i8042>         kbd0            | <piix4_power>   power0         
<i82077>        flp0            | <piix4_usb>     pci_to_usb0    
<i8237x2>       dma0            | <port-space>    isa_bus0       
<i8254>         pit0            | <python>        python         
<i8259x2>       pic0            | <ram>           ram            
<ide>           ide0            | <recorder>      rec0           
<ide>           ide1            | <rom>           rom            
<image>         ram_image       | <text-console>  con0           
<image>         rom_image       | <text-console>  display        

  • Noteworthy objects are cpu0, the processor, and com1, the serial port connected to the con0 console. Try the command help on these objects to see the command available for each.

simics> help con0
Class text-console

  Provided by
    xterm-console
    
  Class Hierarchy
    conf-object -> conf-object -> text-console
    
  Interfaces Implemented
    keyboard_console, event_poster, extended_serial, serial_device
    
  Description
    The text-console class provides a text user interface to the simulated 
    machine's console.

Command List

  Commands
    break    set a string to break on 
    capture-start capture output to file 
    capture-stop stop output capture to file 
    close    close console window 
    disable-quiet enable output redirection 
    disable-window deprecated --- hide console window 
    enable-quiet disable output redirection 
    enable-window deprecated --- show console window 
    info     print information about the device 
    input    send string to a console 
    input-file input a file into a console 
    kbd-abort send a keyboard abort signal 
    list-break-strings list all strings the console will break on 
    no-window deprecated --- show/hide console window 
    open     open console window 
    playback-start start traffic generator 
    playback-stop stop traffic generation 
    quiet    toggle console output redirection 
    read-only toggle read-only mode 
    record-start start recording of output on the console 
    record-stop stop recoding of output on the console 
    status   print status of the device 
    switch-to-serial-link replace text-console with serial link 
    switch-to-server-console replace text console with server console 
    unbreak  stop breaking on string 
    unbreak-id remove a breakpoint 
    wait-for-string wait for a string in a script branch 
    
    
Attributes

  Attributes inherited from class conf-object
    attributes, classname, component, iface, name, object_id, queue
    
  Attributes inherited from class conf-object
    attributes, classname, component, iface, name, object_id, queue
    
  Attributes declared in text-console
    abort, add_title, application, application_args, bg_color, break_string, 
    break_string_id, char_1c_is_abort, console_trace, device, environment, 
    fg_color, height, history, history_length, history_next, history_wrap, input
    , input_buf, input_delayed, input_next, kbd_event_queue, link, next_char, 
    no_window, output_file, output_timeout, quiet, read_only, recorded_string, 
    recording, scrollback, scrollbar, title, trace_file, unbreak_id, 
    unbreak_string, use_xterm_args, vt102_emulation, vt_contents, vt_demo, 
    vt_height, vt_redraw, vt_state, vt_width, width, win32_font, write_delayed, 
    x11_font, x11_fontbold, xterm_args

  • To look at the code we are about execute, use the da (disassemble) command. To look at the location from the current program counter and on, we will use the short form "%pc":

simics> da %pc
v:0x8010870c p:0x0010870c  beq v0,zero,0x8010871c

  • Looking at a single instruction is not very useful, however. There are better ways of doing things, and to find out about them, use the Simics help command:

simics> help da
[... output from Simics ...]

  • Note the "count" parameter that can be given to the command. By specifying this, we can disassemble more instructions:

simics> da %pc 10
v:0x8010870c p:0x0010870c  beq v0,zero,0x8010871c
v:0x80108710 p:0x00108710  nop
v:0x80108714 p:0x00108714  jalr ra,v0
v:0x80108718 p:0x00108718  nop
v:0x8010871c p:0x0010871c  lw v0,20(gp)
v:0x80108720 p:0x00108720  beq v0,zero,0x80108704
v:0x80108724 p:0x00108724  nop
v:0x80108728 p:0x00108728  jal 0x80111ddc
v:0x8010872c p:0x0010872c  nop
v:0x80108730 p:0x00108730  jal 0x801208b0

  • It is often quite useful to know how many instructions have been executed. Since Simics is deterministic, a bug in the execution will appear at the same time each time a program is executed (typically, each time you start a certain build of your operating system from scratch). To see the current time, use the command ptime:

simics> ptime
processor        steps       cycles  time [s]
cpu0       14098153963  14098153963   281.963

  • To get some more detailed information on the execution up to this point, use the print-statistics command for cpu0 (note that you can use tab-completion to quickly type commands):

simics> cpu0.print-statistics

Statistics for cpu cpu0
       User  Supervisor       Total  Description
   12386707 14085767256 14098153963  instructions executed
          0     7867685     7867685  I/O read operations
          0     6936872     6936872  I/O write operations

  • We can use the Simics command-line to provide input to the simulated machine. This is useful to script startup and demo sequences, and test input and output. If, for example, we want to do an ls command in the simulated Linux, we can do it the following way from the Simics command-line (you need to continue the simulation for anything to happen, as the simulated machine needs to accept the input):

simics> con0.input "ls\n"
simics> c

  • That's the end of this part of the lab. To quit Simics, press ctrl-C to get back to prompt (unless you are already at prompt), and give the command quit to quit Simics:

simics> quit
Simics license checked in!
host$

Simics breakpoints during OS boot

The previous step will have taught you how to start and stop Simics, and given a flavor of how it is working with Simics. Now, we'll look more into how Simics can be used to investigate the boot process of an operating system.

  • Start Simics again just like you did before (with the Linux setup).
  • Set a breakpoint on accesses to the malta device, which handles the LCD display (the 8-letter window with red letters). This is done using the break-io command. Note that you do not need to know where the malta device is mapped in memory, which is quite convenient:

simics> break-io malta

  • Check that we have a breakpoint by listing all breakpoints, with break-io -list:

simics> break-io -list
breaking enabled for these devices:
  malta

  • Enable logging by setting a log-size:

simics> log-size size = 10
Setting new size of all log buffers: 10

  • See the debug tips page for more on I/O breakpoint and other Simics breakpoints. You can also read Chapter 8 of the User's Guide for UNIX (or Chapter 7 in the User's Guide for Windows) for more on Simics breakpoints.
  • Start simulation with the continue command. Simics will stop at the first access to the malta device, showing you the type and values of the access. Note that the instruction displayed is the one after the accessing instruction, as the stop takes place after we execute the instruction.

simics> c
[cpu0 -> malta] Write: 0x1f000418 4 0x4c
[cpu0] v:0x802086b4 p:0x002086b4  j 0x802086c0

  • This tells us that a value of "0x4c" (character code for "L") was written to address 0x1f000418, and that the size of the write was 4 bytes. This can be verified by looking at the access history of the malta device:

simics> malta.log
     0  Timestamp: obj = malta cycle = 109011 cpu = cpu0  pc = 0x802086b0
        Write access from cpu0. PA = 0x1f000418 size = 4  data = 0x4c

Only 1 entries listed (no more in buffer)

  • Note the information about the time of the access, who did it (which processor), and which instruction did the access. The accessing instruction was not the jump instruction at 0x802086b4, but the previous instruction at 0x80216a10. Also note that the address of the access is consistent with the memory map of the MIPS machine.
  • To see the accessing instruction, use the da (disassemble) command:

simics> da 0x802086b0
v:0x802086b0 p:0x002086b0  sw v0,0(v1)

  • Do c a few times to see the display of the word "LINUX" build up on the LCD. Each breakpoint will correspond to an additional letter being set.
  • Look at the access history for malta again:

simics> malta.log
     4  Timestamp: obj = malta cycle = 109047 cpu = cpu0  pc = 0x802086b0
        Write access from cpu0. PA = 0x1f000438 size = 4  data = 0x58

     3  Timestamp: obj = malta cycle = 109038 cpu = cpu0  pc = 0x802086b0
        Write access from cpu0. PA = 0x1f000430 size = 4  data = 0x55

     2  Timestamp: obj = malta cycle = 109029 cpu = cpu0  pc = 0x802086b0
        Write access from cpu0. PA = 0x1f000428 size = 4  data = 0x4e

     1  Timestamp: obj = malta cycle = 109020 cpu = cpu0  pc = 0x802086b0
        Write access from cpu0. PA = 0x1f000420 size = 4  data = 0x49

     0  Timestamp: obj = malta cycle = 109011 cpu = cpu0  pc = 0x802086b0
        Write access from cpu0. PA = 0x1f000418 size = 4  data = 0x4c

Only 5 entries listed (no more in buffer)

  • That's enough with malta. Remove the breakpoint using the unbreak-io command, and check that it is gone:

simics> unbreak-io malta 
simics> break-io -list
breaking enabled for these devices:

  • The next step is to let the boot run until it displays "Linux" on the serial console (the regular text window, not the little LCD display). This is done using the con0.break command. We continue immediately to see the effect:

simics> con0.break "Linux"
simics> c
[text-console - con0] Breaking on string 'Linux'
[text-console] Break on string
[cpu0] v:0x801a3e04 p:0x001a3e04  addiu v0,zero,2

  • The con0.break command stops as soon as the given string is displayed on the console. This is very handy when you want to script a program or an OS boot, for example to automatically log in each time the machine is started. Just add a sequence of commands at the end of a .simics file.
  • We can also break when interrupts happen in the processor. We use the break-exception command, telling Simics to stop when the MIPS processor gets an interrupt (note that interrupts are just one of the types of exceptions that we can detect):

simics> break-exception Interrupt
simics> c
[cpu0] (@ cycle 104196745) Exception 0: Interrupt
[cpu0] v:0x80000200 p:0x00000200  j 0x80208100

  • The instruction shown is the one that will be executed as a result of the interrupt. To find the interrupt handler, we will need to single-step from here, using the si command (note that by pressing return in Simics, we simply reexecute the last command). The result looks like this, note that we jump from the interrupt vector into the interrupt handler (more on that below):

simics> si
[cpu0] v:0x80000204 p:0x00000204  nop
simics>
[cpu0] v:0x80208100 p:0x00208100  mfc0 k0,12 sel = 0 (status)
simics> da %pc 10
v:0x80208100 p:0x00208100  mfc0 k0,12 sel = 0 (status)
v:0x80208104 p:0x00208104  nop
v:0x80208108 p:0x00208108  sll k0,k0,3
v:0x8020810c p:0x0020810c  bltz k0,0x8020811c
v:0x80208110 p:0x00208110  move k1,sp
v:0x80208114 p:0x00208114  lui k1,0x8025
v:0x80208118 p:0x00208118  lw k1,-23752(k1)
v:0x8020811c p:0x0020811c  move k0,sp
v:0x80208120 p:0x00208120  addiu sp,k1,-176
v:0x80208124 p:0x00208124  sw k0,140(sp)

  • Run until you hit the next interrupt. Then look at the contents of the cause register to determine the type of interrupt that hit us (look in the MIPS Processor Manual for the details on the cause register). Do cpu0.pregs -all to see all the CPU registers and their values (this is a really long output):

simics> c
[cpu0] (@ cycle 104507910) Exception 0: Interrupt
[cpu0] v:0x80000200 p:0x00000200  j 0x80208100
simics> cpu0.pregs -all
zero  [r0] = 0x00000000      s0 [r16] = 0x00000000
  at  [r1] = 0x80250000      s1 [r17] = 0x00000000
  v0  [r2] = 0x00000008      s2 [r18] = 0x00000000
  v1  [r3] = 0x00002000      s3 [r19] = 0x00000000
  a0  [r4] = 0x00000008      s4 [r20] = 0x00000000
  a1  [r5] = 0x00000001      s5 [r21] = 0x00000000
  a2  [r6] = 0x00000001      s6 [r22] = 0x00000000
  a3  [r7] = 0x00000007      s7 [r23] = 0x00000000
  t0  [r8] = 0x80a5d930      t8 [r24] = 0x00000003
  t1  [r9] = 0x0000003c      t9 [r25] = 0x0000000a
  t2 [r10] = 0x00000018      k0 [r26] = 0x80107f98
  t3 [r11] = 0xffffffe0      k1 [r27] = 0x80107f98
  t4 [r12] = 0x80a5d546      gp [r28] = 0x80106000
  t5 [r13] = 0xfffffffe      sp [r29] = 0x80107f80
  t6 [r14] = 0xffffffff      fp [r30] = 0x00000000
  t7 [r15] = 0x80107e91      ra [r31] = 0x80238388

HI       0x00000004
LO       0x00000000
PC       0x80000200
NPC      0x80000204

Coprocessor 0 registers:
------------------------
PRId     0x00018000
Config   0x80000083
    1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1
    M K K K K K K - - - - M - M M B B A A A A A M M M - - - - K K K
      2 2 2 U U U         D   M M M E T T R R R T T T         0 0 0
      3 3 3 2 1 0         U           1 0 2 1 0 2 1 0         2 1 0

Config1  0x9e180c02
    1 0 0 1 1 1 1 0 0 0 0 1 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1 0
    - M M M M M M I I I I I I I I I D D D D D D D D D - - P W C E F
      M M M M M M S S S L L L A A A S S S L L L A A A     C R A P P
      U U U U U U 2 1 0 2 1 0 2 1 0 2 1 0 2 1 0 2 1 0

Status   0x1000fc03
    0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1
    C C C C R - R - - B T S N - - - I I I I I I I I - - - U - E E I
    U U U U P   E     E S R M       M M M M M M M M       M   R X E
    3 2 1 0           V     I       7 6 5 4 3 2 1 0           L L

Cause    0x00808000
    0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    B - C C - - - - I W - - - - - - I I I I I I I I - E E E E E - -
    D   E E         V P             P P P P P P P P   X X X X X
        1 0                         7 6 5 4 3 2 1 0   C C C C C
...

  • Single-stepping from an interrupt will bring us through the MIPS exception vectors (which contain code) into the actual interrupt handler. Note the purpose of the jump instruction at address 0x00000200 is simply to jump to real interrupt handler elsewhere in memory. The result is similar to this:

simics> si
[cpu0] v:0x80000204 p:0x00000204  nop
simics> si
[cpu0] v:0x80208100 p:0x00208100  mfc0 k0,12 sel = 0 (status)
simics> si
[cpu0] v:0x80208104 p:0x00208104  nop

  • To see what happens to the control registers of the MIPS during the exception handling, we can let Simics use its tracing facilities while the code is running. Try the trace-cr command to start tracing control register changes. Then run some number of instructions using the c command with an argument:

simics> trace-cr -all
simics> c 1000
[cpu0] status <- 0x1000fc00
[cpu0] status <- 0x1000fc00
[cpu0] status <- 0x1000fc00
[cpu0] compare <- 0x1a3ad49
[cpu0] status <- 0x1000fc00
[cpu0] status <- 0x1000fc01
[cpu0] status <- 0x1000fc00
[cpu0] status <- 0x1000fc01
[cpu0] status <- 0x1000fc00
[cpu0] status <- 0x1000fc01
[cpu0] status <- 0x1000fc00
[cpu0] status <- 0x1000fc01
[cpu0] status <- 0x1000fc00
[cpu0] status <- 0x1000fc00
[cpu0] status <- 0x1000fc03
[cpu0] epc <- 0x802383b4
[cpu0] v:0x802383d0 p:0x002383d0  bne v1,zero,0x802383d0

  • To stop tracing, use untrace-cr -all. Note that you can trace only a particular control register by giving its name to the trace-cr command.
  • To stop when a control register changes, use break-cr with the name of a control register or -all, as with all other breakpoint commands (note that as always, your output might be different depending on when in the boot process you execute the Simics commands):

simics> break-cr -all
simics> c
[cpu0] (@ cycle 105007908) Exception 0: Interrupt
[cpu0] v:0x80000200 p:0x00000200  j 0x80208100
simics> c
[cpu0] status <- 0x1000fc00
[cpu0] v:0x802081e4 p:0x002081e4  mfc0 s0,13 sel = 0 (cause)

  • That's it for showing off Simics features as an OS debugger.

Checkpointing

A very powerful feature of Simics is the ability to take a checkpoint of an execution and later continue from that same point. Basically, you write a snapshot of the system state to disk and bring it back into the machine, letting it continue from the point where you left off. We will demonstrate this using the Linux system.

  • Start Simics running Linux as shown previously.
  • Issue the command c 100_000_000, i.e. run one hundred million instructions.
  • When Simics gets back to prompt, look at the state of the machine with commands:
    • How does the text console look?
    • The register contents: cpu0.pregs
    • The execution stats to date: cpu0.print-statistics
  • Now save a checkpoint using the command write-configuration:

simics> write-configuration example-checkpoint
simics>

  • Quit Simics.
  • Next, look in the filesystem for the files generated by the checkpoint:

host$ ls
compiler.mk                   modules
config.mk                     simics
example-checkpoint            simics-eclipse
example-checkpoint.ram_image  student-setup.tar
example-checkpoint.raw        targets
GNUmakefile                   v9-sol8-64

  • Note all the files named example-checkpoint + something else: they are all part of the checkpoint.
  • Now start Simics using the checkpoint, to get back to where we were. Use the -c argument to tell Simics to open the checkpoint:

host$ simics -c example-checkpoint

  • Inspect the state of the machine using the same commands as above. Note that the statistics have been zeroed: when a checkpoint is taken, only persistent machine state is saved, and not the state of statistics gathering.

Hindsight

A new feature in Simics 3.0, Hindsight enables the simulation to run backwards in time.

  • Restart Simics with the Linux machine, as before. Run with c, and press ctrl-C when the Linux command prompt appears.

simics> c
[pci_to_usb0 spec-viol] 4 byte write access at offset 0xc0 in pci_config outside registers or misaligned access
[cpu0] v:0x80108704 p:0x00108704  lui v0,0x8025

  • Set a time bookmark, so that we later can go back in time...

simics> set-bookmark booted
simics> c

  • Now, in the Linux console write:

sh-2.04# rm /bin/ls
sh-2.04# ls
sh: ls: command not found
sh-2.04# 

  • As you can see, we have remove the ls command. We will now use Hindsight to recover ls. Press ctrl-C and type ptime:

[cpu0] v:0x80108704 p:0x00108704  Pending interrupt
simics> ptime
processor       steps      cycles  time [s]
cpu0       3620993844  3620993844    72.420

  • We now use skip-to to find a previous point in time. Note that it is not possible to reverse past the first bookmark.

simics> skip-to bookmark = booted
[cpu0] v:0x80108704 p:0x00108704  lui v0,0x8025
simics> ptime
processor       steps      cycles  time [s]
cpu0       1500602735  1500602735    30.012

  • The system is now in the state it was before the file was erased. Run forward again:

simics> c

  • Simics does not respond to input, but plays back the previous run. This is invaluable when debugging as it keeps the replay deterministic, but in this example we want to forget the future. Skip back again, and use the clear-recorder command:

simics> skip-to bookmark = booted
[cpu0] v:0x80108704 p:0x00108704  lui v0,0x8025
simics> clear-recorder
simics> c

  • Resume the simulation and try ls:

sh-2.04# ls
bin         etc         lib         lost+found  usr
dev         host        linuxrc     proc
sh-2.04# 

  • ls works again!

Testing Simics with an example program

Next, let us try running a small example program on the compsys machine. There is a ready-compiled example timer program included in the installation of the compsys machine, called example_timer.elf which we will use here. This step will also check that your installation of compsys was correct and complete.

  • Look at the script mips-simple-common.simics in targets/mips-simple. This is the script used to start simics. It is quite short; basically all that is done is to set a variable and then hand over to the mips-simple-*.include scripts that does the machine setup.
  • Start Simics using this script (we ignore most of the Simics output in the example below):

host$ ./simics targets/mips-simple/mips-simple-common.simics
Simics started
  Binary loaded: example_timer.elf
  Start address: 80020400

simics> 

  • Start simulating using c. Note that we loaded this program into the memory of the machine without any operating system being part of the process; we are running it directly on the hardware, just like you will with your own operating systems.
  • Stop the program and experiment with the debugging features of Simics. Which devices and interrupts does the program use?
  • Note that you will be using some convenient scripts to run your own programs in Simics, as described in the compilation introduction lab.

Scripting Simics

Optionally, you might want to investigate the possibilities of extending the Simics command line using scripting. As example here, we will add a command that stops execution as soon as an eret instruction is found.

To start, we will set a breakpoint on eret instructions using the command line interactively. This process relies on a breakpoint filtering feature in Simics (to find more information on the commands, do help break and help set-prefix).

  • Set a breakpoint on the entire memory containing instructions (in virtual addresses for the Linux example, the memory is much smaller for the compsys machine):

simics> break -x 0x8000_0000 0x0800_0000
Breakpoint 1 set on address 0x80000000, length 134217728 with access mode 'x'

  • If you try executing, you will stop on every instruction. Which is not very practical.
  • We can modify this breakpoint to match just specific instructions. This is done using one of the commands

set-prefix, set-substr, or set-pattern. For the eret instuction, prefix is the most appropriate. Note that we need to specify the ID number of the breakpoint to modify:

simics> set-prefix 1 "eret"
simics> list-breakpoints
 Id Type     Enb Start              Stop                 Hits Space
  1 virt-x   yes 0x0000000080000000 0x0000000087ffffff      0 primary_context
    Prefix: eret

  • Let the simulation run. After a while, it should stop when it finds an eret instruction:

simics> c
Code breakpoint 1 reached.
[cpu] v:0x800205a0 p:0x000205a0  eret

  • This is quite a lot of typing to do each time such a breakpoint is desired. Instead, we can create a small script-file that does the job for us. Open up an emacs or other text editor, and enter the commands used above on consecutive lines:

break -x 0x80000000 0x08000000
set-prefix 1 "eret"

  • Save this under a name (like "setbp.simics") in the Simics directory you are currently using (likely targets/malta or targets/mips-simple).
  • Quit Simics and restart it, so you have a new fresh machine.
  • Load the command-file you saved using the command run-command-file:

simics> run-command-file setbp.simics

  • Check that the breakpoint triggers as before when your program executes.

As you might see, the above solution only works for a single breakpoint, since we have hardcoded the breakpoint ID number in the argument to the set-prefix command. The only way to fix this limitation is to move to Python scripting and use the Simics API (as described in the Simics User's Guide. Feel free to explore this aspect of Simics on your own.

Anyway, putting common command sequences into script files is handy for repeating tasks with Simics, or to automate testing. When doing the labs, the run.simics file and the run.sh script will be used. These files can be extended with new commands during project development.

Updated  2009-03-25 20:21:58 by Karl Marklund.