260 likes | 272 Views
Develop a virtual machine interpreter for the BRAIN98 computer, including an assembler, storage, CPU registers, and instruction set. Test with non-trivial programs.
E N D
Project BRAIN • Usually done in groups of two • Each student responsible for implementing parts 1-4 with their partner. • Each team must demonstrate working version of each part to TA and/or instructor. • For each part of the project you must provide: • Commented, well-formatted source code for the BRAIN98 virtual machine • Commented source code for the BRAIN98 programs
You must provide a write-up for each part of the assignment. • This must describe the group’s efforts to address each step in the assignment and answer all questions asked in that part of the assignment, including any directions to discuss particular topics. • For some parts, you are also asked to include graphs, etc. • The documentation must be provided to get full credit. • The maximum credit possible without documentation is 80%.
The documentation needs to address at least the following points: • What were the main issues that had to be addressed and how did you address them? • Provide an overview of the structure of their program. How does the program work? • List any special features, bugs, etc. in the program. • What did you learn with respect to the topics studied in the class? • Anything else you feel is important to discuss.
Project Part 1: A Virtual Machine Interpreter for BRAIN98 • Step 1: Write a program that emulates a hypothetical computer, called BRAIN98. T • this virtual machine interprets BRAIN98 assembler code. • In general, you may write your emulator in the high-level language of your choice, but you must clear your choice of language with me first.
Project Part 1: A Virtual Machine Interpreter for BRAIN98 • Step 2. Test your virtual machine with at least 3 non-trivial programs written in BRAIN98 machine language. • Note: “Non-trivial” means just that. • It is unacceptable for your programs to simply exercise the instruction set of the machine. • Some good choices from past years include • computing Fibonacci numbers; • multiplication of large (> 4 digits) numbers; • sorting; • prime number detection.
The Virtual Machine • Storage consists of a maximum of 100 words, addressed from 00 to 99; • each word is divided into four one-byte units, where a byte may contain any character acceptable by the host machine (i.e., the computer running the emulator). • The CPU has three registers: • a four-byte (four-character, really) general register R, • a one-character “Boolean” toggle C, which may contain either “T” (true) or “F” (false), • and a two-character instruction counter IC.
A word in memory may be interpreted as an instruction or data word. • If the word is an instruction, • the operation code (“opcode”) occupies the two high-order bytes of the word, • and the operand address (if needed) appears in the two low-order bytes. • The virtual machine will assume that the first instruction of the program appears in location 00 of memory.
Instruction Result Description • LR loc R := [loc] Load register • LL loc R := R:1||R:2||[loc]:3||[loc]:4 Load low (low-order bytes of R) • LH loc R := [loc]:1||[loc]:2||R:3||R:4 Load high • SR loc [loc] := R Save register • CE loc if R = [loc] then C := ’T’ else C := ’F’ Condition equal • CL loc if R < [loc] then C := ’T’ else C := ’F’ Condition less than • BT loc if C = ’T’ then IC := loc Branch true (to loc) • BU loc IC := loc Branch unconditional • GD loc for i=0 to 10 (loc - (loc % 10)) + i:= data from file Get data: e.g., if loc = 43, then this reads the next 10 data items from the file and puts them in 40– 49 • PD loc for i=0 to 10 Print data at (loc - (loc % 10)) + i Print 10 values in memory. If loc = 58, then this will print mem loc. 50- 59. • AD loc R := R + [loc] Add • SU loc R := R - [loc], R >= [loc] Subtract • MU loc R := R * [loc] Multiply • DI loc R := R / [loc], [loc] > 0 Divide • NP loc none Null operation (no-op) • H machine stops Halt (does not require an operand)
loc is a two-character memory address, • [loc] means the contents of memory location loc, • [loc]:i means the ith character of the contents of loc, where the characters are numbered 1234, • R is the register, • R:i means the ith character of the contents of the register, • IC is the instruction counter, • C is the Boolean toggle, • || means concatenation • R:1||R:2 means the first byte of R concatenated with the second byte of R.
Notes on Arithmetic Operations (AD,SU,MU,DI) • An arithmetic op on non-numeric data fields is undefined. • Divide by zero is undefined. • A negative result (for SU) is undefined. • Overflow values (for AD and MU) are lost. • Important: • Undefined behavior can be handled by the implementer in any reasonable way.
Your program will read BRAIN98 input from a file. It will act both as a loader for the virtual machine and as an I/O processor. • The BRAIN98 input file has the format: • Line 1: Header, identifying the kind of file it is. This is the string “BRAIN98”, with the “B” starting in column one. • Lines 2–n − 1: The BRAIN98 program. • Enter instructions as 4-character strings, one per line, starting in the first character of the line, with no blanks between the operator and operand. • After at least one blank, a non-interpretable comment may complete the line. • Whatever is in the first four characters of each of these lines will be loaded by your program into the corresponding memory location of the virtual machine.
Line n: Data separator. This line separates the BRAIN program from the data that will be read by GD instructions. This line consists of the string “DATA”, with the “D” starting in column 1. • Lines n+1–end of file - 1: Data. Each of these lines contains 10 input items (i.e., 10 4-characterwords of data) to be loaded into the virtual machine’s memory by GD instructions. • There are no spaces between words on this line. Note that this means that the first forty characters of the line, regardless of what is in them, is considered data! • Last line: This is the end-of-file indicator for your program. It consists of the string “END”, with the “E” beginning in column 1. In later parts of the project, the format will be changed to allow multiple BRAIN programs to reside in a single file.
Deliverables • Project demonstration • Hardcopy of: • BRAIN source • BRAIN98 program source code • Documentation as discussed above. See syllabus for the policy about grammar/spelling/typos. • You will turn in the electronic version of your project electronically via Blackboard (or equivalent).
Grading • Program (interpreter): 75% • BRAIN programs: 15% • Write-up: 10%
Recall Parameters to main in C. main(int argc, char *argv[]) //also char *envp[] { ………………………………..} argc: Number of command line parameters (always at least 1). argv: Array of pointers to command line parameters. Each parameter is a null terminated string.
Example: % ./a.out 1 4 main(int argc, char *argv[]) { ………………………………..} argc = 3 argv points to an array with three elements, each of which is a pointer to a null terminated string.
argv “a.out” “1” “4” Example: % ./a.out 1 4
The name of the program is always contained in element 0 of argv. Ex: Want to print out name of program (inefficiently): char *ptr ; ptr = argv[0] ; while (*ptr != ‘\0’) printf(“%c”, *ptr++) ;
Exec Family of System Calls • Used to begin a processes execution. • Overwrites process (core) image of the calling process with that of called program. • Several flavors, use the one most suited to needs. • int execv( char *path, char *argvec[]) ; • int execl(const char *path, const char *arg0, ..., const char *argn, char * /* NULL*/);
exec Function calls int execv( char *path, char *argvec[]) ; path: Can be an executable program in your directory (application code) or a system program such as ls, cd, date, ………….. argvec: Array of pointers to NULL terminated strings. First element should always be the name of the program, last element should always be NULL.
Example fork/exec pair main (int argc, *argv[]) { int my_pid ; char *args[3] ; my_pid = fork() ; if (my_pid ==0) { args[0] = “./a.out” ; executed by args[1] = “2” ; child process args[2] = NULL; execv(“./a.out”, args) ; printf(“OOOpppssss.\n”) ; } else printf(“Not a problem!\n”) ; executed by parent }
Program a.out will begin to execute and will have the following parameters to main: argc = 3. argv[0] = ./a.out argv[1] = “2”
Process Management System Calls • wait() Blocks parent process until all child processes have terminated • wait(pid) Blocks until a particular child process terminates. • exit() Terminate the process and de-allocate its resources.
Very Simple Shell while(1) { type_prompt() ; read_command(command, parameters) ; if (fork() != 0) // I am the parent wait() ; else { execv(command, parameters) ; printf(“OOOPPPSSS\”) ; } }