Project 1 Index
Build a program that emulates a subset of the X86 ISA by executing programs encoded in OCaml datatypes.
project1.tar.gz contains all that you need to get started with this assignment. Extract it such that x86interp.ml is located at cis341/projects/x86interp/x86interp.ml. (The cis341/ convention is explained in the tools page. Make sure the OMakefile at cis341/projects/OMakefile includes the x86interp project in the PROJECT_SUBDIRS list: PROJECT_SUBDIRS[] = x86interp

This is a group project. Groups of size 1 or 2 are acceptable.

Implement the interface declared in x86interp.mli. You should not change the interface file, but it's fine to change the code we've already provided in x86interp.ml. In particular, for the correctness tests, we will only check those functions exposed in the .mli. (In fact, since the tests are in a separate module, OCaml wouldn't let us do otherwise.) This means that, for example, you are free to define map_memory however you wish (or even to delete map_memory from the code). Its signature is provided only as a hint.

The code we have provided gives you a design to start from. It manages control flow using exceptions and the OCaml stack. Should you decide to use this code, you will need to implement the currently-failwith instructions in single_insn (and the helper functions that the provided code for Mov, Jmp, Call and Ret depends upon). You must still implement the interface, including condition_matches, but you may trust that the code for execute_mbb and interp_mbbs is complete modulo the functions it calls.

The code provided in x86interp.ml describes some assumptions that you can make about the code your simulator will be expected to execute. To summarize:

  • Memory addresses are 32-bit aligned. (If not: raise X86_bad_memory_location).
  • Memory ranges from xFFFFFC00 to xFFFFFFFF. Bad accesses should raise X86_bad_memory_location.
  • All memory and registers are initialized to 0, save for Esp which is initialized to xFFFFFFFC.
  • Displacements in indirect operands may only be constant int32s. (If not: raise X86_bad_memory_location).
  • Label operands are not permitted (except when the operand is the immediate target of a branch). If you encounter a label operand, raise X86_bad_memory_location.
  • You can't set immediate int32s (CImms). If someone tries, raise X86_bad_memory_location.
  • You only have to update the flags OF, SF and ZF. If an instruction indicates that one or more of these flags is undefined, you do not need to worry about what value (if any) you assign them.
  • Don't worry about setting condition codes for the shift instructions (Shl Shr Sar).

Certain other cases are already handled by the provided code:

  • Control flow instructions may only branch to CLbl operands. If any other branches are attempted, raise X86_bad_insn.
  • All instruction sequences will either terminate with Ret or will jump to other instruction sequences. If an instruction sequence does not terminate in this way, raise X86_no_ret
  • If you encounter the Ix instruction, raise X86_bad_insn.

Part of your grade will be based on testing. Some example tests and utility functions are provided in x86interptests.ml. For this assignment, we require that you define at least 10 new unit tests. (These must be sufficiently different from one another to count— tests like 1 + 1 == 2, 1 + 2 == 3, 1 + 3 == 4 are too similar to be useful). A good way to hit and surpass this requirement is to write tests for each instruction. You are required to share at least one of these tests on the class mailing list and are encouraged to share the rest. You may count tests that others write toward your 10, but remember to cite the authors.

We also ask that you write a significant functional test of your interpreter. This test should at least demonstrate some interesting control flow (eg, a loop with a conditional guard). A good strategy is to choose and implement a function (like factorial). We will add these tests to our grading test file and run them on all projects. You should not share this test (but may share other tests of equal size).

Edit the included readme.txt file, making sure to fill in your name(s) and email address(es).

You should also spend some time to ensure that your code is readable and well-commented. We have some suggestions and requirements for your programming style. You will definitely lose points for the file submission requirements (code must compile, 80 column limit, no tabs); however, barring any particularly egregious cases, you may take the remaining rules as suggestions.

The grading breakdown for this project is as follows:

  • 65 points: Our correctness tests (including those we have given you).
  • 10 points: Code style, readability and documentation.
  • 5 points: Your substantial secret unit test.
  • 10 points: Other unit tests; sharing a test on the class list.
  • n points, where n is the number of on-time submissions: Everyone's functional tests.
  • Max of +5 extra credit points: clever implementations, tricky tests and so on.

Remember that your raw score will be scaled— that is, more difficult assignments will be worth more than less difficult assignments, even if the more difficult assignment has fewer available points.

Only one submission is necessary per group.

First, make sure to clean your project with omake clean. All of the files you've written should be in projects/x86interp. Submit your assignment on ENIAC by switching to the projects directory and typing: turnin -c cis341 -p project1 x86interp Verify that you've submitted your files with: turnin -c cis341 -v -p project1 You can re-submit your work any number of times, but only the last submission will be counted. New submissions completely overwrite old submissions— so if you're missing a single file, make sure to resubmit your entire project. Check the main course page for information about late policies.