Carnegie Mellon
SCS logo
Computer Science Department

15-410 Simics Environment Guide

Getting to know your debugger is a deeply useful skill. This documentation intends to expose some of the internal knobs, bells, and whistles of the Simics environment for 15-410 for "advanced" use cases of varying kinds.

Invoking Simics

The usual simics command, simics46 has many variants and silent features. In particular, there is something of a tradition that the TAs will create simics46-$ which may contain debugging, testing, or experimental code. If you encounter a problem, one or more TAs may try writing code to help out and may ask you to run their version of the simics environment for a while.

Most features of the Simics environment are controlled by knobs in the environment at time of invocation:

If this environment variable contains a nonempty string, Simics will spawn an xterm for a text console rather than its graphic console. This may speed simulations where the X display is remote. Because this console is low-fidelity, it is usable for the thread library and kernel projects, but not for the game project!
If the value of this environment variable can be converted to an integer, simics will attempt to run with that many CPUs. Results are not necessarily well behaved for values outside of 1 to 15.
If this environment variable is nonempty, Simics will instead simulate an amd64 ("hammer") system. The default is a Pentium 4 system.
If this environment variable is nonempty, Simics will watch the wall clock and attempt to keep the system elapsed time equal to the wall clock elapsed time, rather than allowing events to happen as fast as possible. This is generally only useful for simulations which are mostly idle, notably during Project 1.
Names a file to use as the backing store of the primary IDE bus's master disk.
The size of the primary disk image
Essentially any other knob of the simics environment can (though may not be, obviously... no, we won't give you a PPC core) be added on reasonable request.

Adding Code To The Simics Environment


You MUST NOT (let's say that again: MUST NOT) depend on code you add to the simics environment for the correctness of your kernel (except under very, very rare exception which must be confirmed by the professor(s)), as the graders will disable your modifications before invoking simics to grade your code. However, we will read this code, as with the rest of your handin. Landing malicious code in a handin via this mechanism, as any other, is a breach of academic conduct and will be handled as such.

On an only slightly less dire note, you should make an effort not to get lost in this. Simics is really, really big, and contains tons and tons of features, nooks, crannies, and traps. Remember that your objective is to write a 410 assignment, which is probably not a Simics module. This is intended as debugging tool, and like any tool, it should not be used when inappropriate. Moreover, as the power of this tool comes from its flexibility and therefore bestowes upon this tool a very steep learning curve, it should only be used when lesser tools are in some way inadequate for the job at hand.

Where do I do this

The 410 Simics environment will slurp in all python (*.py) files in the root of your project directory (alongside your README.dox, that is) that begin with "410mods-dynamic-". These files are loaded in alphabetical order and after the core 410 environment is up and running. If it all goes well, you'll see a message like
"--> Working directory dynamic modifications loaded from $PATH/"
This is a natural extension of the same mechanism applied to 410mods-dynamic-*.py files in the simics environment directory and is new this semester for student usage.

What do I do?

Step one, as always, is to familiarize yourself with the contents of the manual. However, as the reference manual is nearly 3000 pages long, it may help to use these examples as a starting off point and see where this takes you. Your TAs will, in general, assist you when they can, but it is remarkably easy to fall beyond the local-knowledge horizon and end up forging on alone.

Adding a custom breakpoint

Breakpoint handler functions take four parameters:
arg Per-HAP callback data, unused in the current 410 environment
obj The configuration object which caused this breakpoint
brknum The breakpoint number
m The memory transaction associated with this breakpoint. See the Simics reference manual for more information.
Here's a way to add a breakpoint that stops only when the address it is watching takes on any of a set of values and traces all values except a specified set. It demos how to add breakpoints to the simulation environment within the breakpoint routing feature provided by the 410 environment.

single_address = 0x01234567             # Breakpoint address
watch_size = 4                          # Breakpoint size
trace_silence_values = [ 0x00c0ffee ]   # Don't show these values
break_on_values = [ 0xfeedface ]        # Stop the simulation on these values

def handle_my_breakpoint(arg, obj, brknum, m):
  # Filter out control messages
  if SIM_mem_op_is_control(m) :
    print "Custom breakpoint got a control transaction, ignoring!"
  # Extract the CPU
  if not SIM_mem_op_is_from_cpu(m) :
    print "Custom breakpoint got a non-CPU initiator!"
  cpu = m.ini_ptr
  ### This depends on 410 segmentation!  The correct way is, much like x86,
  ### a lot more putrid.
  pa = SIM_logical_to_physical(cpu, Sim_DI_Data, m.logical_address)
  # Get size of transaction or fall back
  size = m.size
  if size == 0 :
    print "WARNING: Zero size memory transaction is not a control transaction!"
    size = watch_size
  # Read out the current value at that physical address
  # which we assume to be a 32 bit value (thus the 4)
  cur_dat = SIM_read_phys_memory(cpu, pa, size)
  # Construct informative message
  str = "Custom breakpoint %d hit at l:0x%x with size %d, saw there %x" \
      % (brknum, m.logical_address, m.size, cur_dat)
  # If the value read matches our break-on value, then stop the world.
  if cur_dat in break_on_values :
  elif not cur_dat in trace_silence_values :
    print str

nbp = SIM_breakpoint(conf.primary_context,  # Watch the primary context
                      Sim_Break_Virtual,    # We're interested in Virtual addr
                      Sim_Access_Read,      # Read access
                      single_address,       # The address in question, above
                      watch_size,           # How big of an area are we watching?
                      Sim_Breakpoint_Simulation # This breakpoint is part of
                                                # the simulation environment.

# Register this with the breakpoint dispatch system
breakpoint_handlers[ nbp ] = handle_my_breakpoint
# Inform the user of our decision
print("Custom breakpoint registered on p:%x with break values %s as %d"
        % (single_address, break_on_values, nbp) )

Adding a custom HAP handler

HAP handler functions take tree parameters:
arg Per-HAP callback data, unused in the current 410 environment
cpu The current CPU of the environment
param On X86 this is always zero

[Last modified Friday September 05, 2014]