SimIt-MIPS |
Users' Guide |
InstallationTo install, first untar the source by tar xzvf SimIt-MIPS-1.0.tar.gz Then build the source code by cd SimIt-MIPS-1.0 ./configure make make install After these steps, the ./build/bin directory contains the following programs:
To test the installation was successful type ./build/bin/emips test/wc configure The above command simulates the UNIX utility wc. If the simulator is installed correctly, you should see the line count, word count, and character count of the file configure. If one prefers other installation directory than the default build, one can specify the prefix configuration flag. ./configure --prefix=<PREFIX path> For convenience of referencing the simulator commands, one can include the bin/ directory into the environment variable PATH by typing in bash export PATH=$PATH:<PREFIX PATH>/bin or in csh setenv PATH ${PATH}:<PREFIX PATH>/bin BACK TO INDEX |
Quick StartSimIt-MIPS reads ELF32 little-endian MIPS binaries. The binaries must be statically linked. See the crosstool page for more information on building a cross MIPS compiler. The mipsel configuration with gcc-3.3.4 and gibc-2.3.2 should work fine. This section uses a simple C program to demonstrate the essential steps involved in using the simulator. Below shows the example program: #include <stdio.h> int main() { printf("Hello World!\n"); return 0; } Now compile the program using the ELF32 MIPS cross-compiler. Remember to statically link the binary. The command should be something like: mipsel-linux-gnu-gcc -static -o hello_world hello_world.c The compiler generates the hello_world MIPS32 binary. Assuming that the <PREFIX>/bin directory has been added to the environment variable PATH, one can simulate the binary by typing emips hello_world The interpreter emips will output "Hello World!" in the standard output. Usage of the interpreter is described in more detail in Section Interpreter. One can also build a static-compiled simulator for the program (more accurately, binary-translate the program) by typing build_scs hello_world The above command will take several minutes to finish since building the static-compiled simulator involves compiling dozens of C++ functions. The building process will create a folder named hello_world.scs under the current working directory. In the folder, there is a script hello_world. To run the translated program, simply run the script. ./hello_world.scs/hello_world Section Static compiled simulation gives a complete description on building static-compiled simulators. Lastly, the dynamic-compiled simulator can be invoked by emips_jit hello_world In this example, the dynamic-compiled simulator interprets the whole program since hello_world is too short to trigger run-time compilation. A full description of the dynamic-compiled simulator is provided in Section Dynamic compiled simulation. BACK TO INDEX |
InterpreterCommandline OptionsThe default syntax for running the interpreter is: ./emips <program name> <program arguments> By default, the interpreter will print out running time information and instruction counts. If one wants SimIt-MIPS to print out error messages and system call information, run it in verbose mode by typing ./emips -v <program name> <program arguments> Often simulation can take a very long period of time. To avoid waiting indefinitely, one can truncate simulation by setting an upper bound of the number of instructions to simulate. ./emips -m [number of instructions] <program name> <program arguments> Built-in DebuggerSimIt-MIPS also has the ability to trace the target programs. To start SimIt-MIPS in debugging mode type: ./emips -d <program name> The following instructions are available at the debugging prompt:
We again use the program hello_world as an example. Although the debugger performs run-time disassembly, it is sometimes useful to create a dump of the assembly code for the target program before debugging. The MIPS cross objdump can be used to create the dump. It is normally built along with the cross-gcc. mipsel-linux-gnu-objdump -d hello_world >hello_world.dump Now start the debugger with the command: ./emips -d hello_world One should now see the debugger prompt ">". At the prompt, one can type any of the commands above. We assume that, from our dump file, we learn that the main function starts at address 0x004003e0. We can instruct the debugger to run until the main function by typing: >g 4003e0 At this point, if we want to see the first 10 instructions in main, we type: >u pc Suppose we want to inspect certain memory accesses and we notice that the 5th instruction is a memory store. 0x004003f0 : 0xafbc0010 sw $gp, 16($sp) We can step through the first 4 instructions with: >t 4 To inspect the contents of the registers, we can simply type: >r From the screen printout, we can learn value of the stack pointer, $sp, which is used in the sw instruction. Assume its value is 0xbfffbda8. We can observe the memory contents from this address by typing: >d bfffbda8 The command will display 256 bytes of memory. So we can find the contents of memory that the program is accessing. If we decide that the contents of memory is incorrect, we may want to go back and check previous memory accesses. We can now terminate the debugger by typing: >q and restart it to trace back to the first memory access. Obviously there are more complicated debugging scenarios than this. Hopefully the above example will get you started. GDB InterfaceA more powerful debugging option is the GDB remote debugging interface. This is currently in an experimental phase bus has already proven useful. To enable this debugging approach, one must first build a GDB client that supports the MIPS target. The GDB client receives user commands, sends control instructions to the MIPS interpreter, modifies/retrieves register and memory values, and displays debugging information to the user. We built a GDB 6.3 client using the following configuration options "--host=i686-pc-linux-gnu --target=mipsel-linux-gnu" To enable the gdb interface of the interpreter, type: ./emips -gdb 127.0.0.1:1234 <program name> <program arguments> & The "-gdb" option specifies an IP address and a port. Here we use port 1234 on the local machine (127.0.0.1) to communicate between GDB and the interpreter. We then start GDB by typing mipsel-linux-gnu-gdb <program name> (gdb)target remote 127.0.0.1:1234 (gdb)break main (gdb)cont The above commands sets a break point at the main function and starts simulation. Most common GDB commands are supported. The approach also works with DDD for graphical debugging. BACK TO INDEX |
Static compiled simulationThe static-compiled simulator breaks up the target program into small pages, and translates each page into a C++ function. The C++ functions are then compiled and linked together to form the static-compiled simulator. The process is often called binary translation. In SimIt-MIPS, the program emips_decomp is used to perform translation from MIPS binary to C++. However, it is not recommended that users invoke it directly. Users should use the script build_scs instead. The script not only invokes emips_decomp to do translation, but also compiles the translated code and link them with support routines into a full simulator. The command line format of the script is build_scs [-c] [-v] [-l num] <program> The meaning of the optional arguments are listed below:
The arguments must precede the path/name of the MIPS32 binary program to translate. The page size will be rounded up to the nearest power of 2. Additionally, if the page size is less than 512, it will be hard limited to 512. A larger page size means less but larger functions. A overly large page/function size may cause significant slowdown of G++ since many modern compiler optimizers have super-linear complexity. The build_scs script will generate a directory named <program<.scs under the current working directory. The directory contains another script with the same name as the original program. The script can be invoked in the same way as the original MIPS program. For example, for the MIPS32 program wc, the script will generate the directory wc.scs and another script named wc under the new directory. One can then invoke wc.scs/wc in exactly the same way as one would invoke wc on a MIPS platform — the same program arguments to wc should be supplied to wc.scs/wc. BACK TO INDEX |
Dynamic compiled simulationThe dynamic-compiled simulator combines the functionality of the interpreter and the static-compiled simulator. It interprets the program at the beginning of the simulation. Meanwhile it profiles the simulated program by keeping a counter for each page of the code. The counter records the cumulative number of simulated instructions in the page. If the number is beyond a predefined threshold, then this page is deemed hot and is translated. Translation is performed in two steps. First the page is translated to a C++ function. Next the C++ function is compiled into a shared library and linked to the simulator itself. Compilation of the C++ function can be done by the simulator itself, or can be distributed to a remote translation server. Obviously, the use of more translation servers means faster simulation speed. The dynamic-compiled simulator can be invoked by the command emips_jit. The command has the following format: emips_jit [-t num] [-l num] [-f fname] [-c] [-m] [-v] [-w] [-h] <program> <program arguments> The meaning of the command line arguments are explained below:
Translation of code pages into dynamic libraries is performed by GCC. Due to the slow speed of GCC in compiling C++ code, For small programs it may take emips_jit longer to simulate than emips. But for large programs, the translation overhead will be sufficiently absorbed and emips_jit will outperform emips. The dynamic-compiled simulator will create a folder $HOME/.emips to cache translation results. If a program has been simulated once, subsequent simulation may be much faster because shared libraries in the cache can be directly loaded on simulation start. The translation server program emips_jit_server has the following usage format. emips_jit_server [-v] [-p portnum] [-h] The commandline options are listed below.
To perform dynamic-compiled simulation using multiple workstations, one need to first ensure that they can communicate with each other using UNIX socket. Firewalls may need to be partially turned off. Then the translation servers can be started first, followed by the simulator emips_jit. The -f option of emips_jit must be used to specify the address of the translation servers. The configuration file should one or more lines. Each line specifes the address of one translation server in the following format. IP_address port_number More technical details of the dynamic-compiled simulator have been published in conference proceedings. See References for information. BACK TO INDEX |
Reference
BACK TO INDEX |
If you have further questions, please contact the authors at weiqin@gmail.com or jderrico3@gmail.com. Check out Simit-ARM too! |