CS520
Spring 2016
Program 3
Due Wednesday March 9


Write an emulator for the RISC-V machine language.

Your emulator only needs to handle a subset of the RISC-V RV-64I base instruction set, plus two instructions from the "M" standard integer multiplication and division instruction extension. The exact list of instructions you need to support is given below.

The RISC-V machine code will be in a 64-bit, little-endian ELF file.

Your program should take a mandatory command-line argument, the name of the ELF file to be disassembled. This argument can optionally be preceded by an additional command-line argument, "-v", which indicates verbose output should be provided.

The goal of your program is to emulate the execution of RISC-V programs. You will need to maintain an array of signed long integer values to implement the RV-64I registers. Initialize these registers to all contain zero. You will also need to maintain a 64-bit variable to implement the RV-64I pc (program counter). Initialize the pc to point to the first instruction in the program.

You should implement a fetch/execute cycle, repeatedly fetching and emulating the execution of instructions until one of the following things happens:

At this point, end your emulation, print a line to stdout indicating why the emulation is ending ("normal termination", "unknown instruction", "pc out of range", or "misaligned pc"), display the contents of the RV-64I registers (but not the pc) to stdout, and terminate the program. Your register display should look exactly like this:


 x0-x3 : 0000000000000000 00000000021C2054 0000000000000000 0000000000000000
                        0         35397716                0                0
 x4-x7 : 0000000000000000 0000000000000000 0000000000000000 0000000000000000
                        0                0                0                0
 x8-x11: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
                        0                0                0                0
x12-x15: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
                        0                0                0                0
x16-x19: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
                        0                0                0                0
x20-x23: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
                        0                0                0                0
x24-x27: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
                        0                0                0                0
x28-x31: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
                        0                0                0                0

That is, four registers are displayed at a time, on one line in unsigned hex (with all the leading zeros) and on the following line in signed decimal (with no leading zeros). On each line the registers are displayed in increasing register number order. The hex digits A-F should be displayed as capital letters.

When the emulator is run in verbose mode, each instruction should be displayed to stdout before it is executed. Each instruction should be displayed on its own line. The line should have no leading spaces and should begin with a display of the pc as an decimal integer offset from the beginning of the program in units of instructions. (The first instruction is at offset 0, the second instruction is at offset 1, etc.)

Each instruction should be displayed using the exact format used on pages 50-51 of the RISC-V User-Level ISA Specification v2.0, with one exception: print the opcode in lowercase. (The format to be followed is listed on the far right-hand side of the two pages cited.)

Note that there is a single space separating the opcode from the operands, and there are no spaces following the commas separating the operands. Also, please do not print any blank lines, any header lines, or anything else.

The immediate constant values should be displayed in decimal, and the value displayed should be the value intended, not the value of the bits in the immediate constant field. For example, the immediate constant value in the SB instructions is shifted left 1 position (multiplied by 2) to get its intended value. Immediate constants are signed values.

Register numbers should be displayed in decimal with a lowercase "x" prepended.

Also, please do not print any blank lines, any header lines, or anything else. We plan to use automated output file checking (the diff or cmp commands), so be sure to follow this specification exactly. And please raise questions if you do not think these directions are specific enough.

You should make your program robust so that it can handle errors such as:

Put your source code in a single file called "emRISCV.c".

In the ~cs520/public/prog3 directory there are ELF files containing RISC-V machine code. This directory also contains some "dump" files that contain the expected stdout output for the corresponding ELF files when in verbose mode, as well as the assembly language files used to create the ELF files. (Note that the verbose mode of the emulator will not re-create the assembly language exactly.)

The RISC-V assembler is available on agate as ~cs520/bin/asRISCV. Run it with the "--help" flag to learn more about using it. Basically you need to give it a file to be assembled, which should use the ".s" extension, and you should use the "-o" flag to set the output file name.

Your program will be graded primarily by testing it for correct functionality:

You must emulate the addi and sbreak instructions before attempting any of the others, because they will be used to test the other instructions.

Leave the Lab 5 and Lab 6 output to stderr on for your Program 3 submission. But be sure that this output goes to stderr and that the emulation output (both the verbose output and the final register dump) goes to stdout.

Remember, you may lose points if your program is not properly structured or adequately documented. Coding guidelines are given on the course overview webpage. I also want to see that you applied the principles of problem decomposition, incremental development and incremental testing. Leave your debugging output in your code, but disabled, when you do your final assignment submission.

Your programs will be graded using agate.cs.unh.edu so be sure to test in that environment. Your programs will be compiled using these gcc flags: -g -Wall -std=c99.

Your programs should be submitted for grading from agate.cs.unh.edu. To turn in this assignment, type:
~cs520/bin/submit prog3 emRISCV.c

Submissions can be checked by typing:
~cs520/bin/scheck prog3

This assignment is due Wednesday March 9. However, since the midterm is also that day, late programs will be accepted without penalty until 12noon on Saturday March 12. No programs will be accepted after 12noon on Saturday March 12.

Remember: as always you are expected to do your own work on this assignment. Copying code from another student or from sites on the internet is explicitly forbidden!


Last modified on February 28, 2016.

Comments and questions should be directed to pjh@cs.unh.edu