CSC 7B/FC Programming Assignment. Due One Week From Date Assigned Study the program machine.fs, which implements "Abstract Machine AM7B" in F#. Compile machine.fs and run the sample program test1.7b with (mono) machine.exe < test1.7b (feed file to stdin) You should see that top of stack holds 17, which is the result of the computation. The assembler skips blank lines and lines that start with '#'. As a hot shot engineer, you're not impressed with AM7B. You decided to implement a much more powerful machine: AMHS (abstract machine for hot shots). Your machine is to have the following features lacking on AM7B: New type of operand: [cx] refers to the memory content at location addressed by cx (in the program, this is RAM.[REGS.[2]]). Because of the way that your imaginary CPU is wired, only the cx register can be used to address memory, so [2] and [ax] are illegal operands. New Instructions: add 3 bx : ALU operations can have an immediate (constant) source operand mov 3 ax : move immediate value to register (REGS.[0] <- 3) mov ax bx : move register to register (REGS.[1] <- REGS.[0]) mov ax [cx] : move register to memory location addressed by cx Only register cx can be used to address memory mov [cx] ax : move memory to register. Memory to memory ops are not allowed (this is a RISC machine) jnz 3 : jump to instruction 3 if the value in register cx is not zero (REGS.[2] <> 0). The first instruction is the 0th. With these instructions your machine becomes a true Turing Machine, with random access to memory and the ability to execute algorithms. Furthermore, the idiv (integer division) instruction should be modified so that 'idiv ax bx' will have the effect: bx = bx / ax // quotient in the destination register dx = bx % ax // remainder in dx register The dx register thus serves a special purpose with respect to the idiv instruction and should NOT be used as a destination register for idiv. (strings can be compared with = and <>) You may implement other instructions to prove that you're a hot shot, but these are the minimum. Test your machine on test3.7b: (mono) machine.exe < test3.7b mov 8 cx mov 3 bx add 2 bx mov bx [cx] mov [cx] ax push ax This program should store 5 in RAM.[8] and push 5 on the stack ... and this program (test4.7b): mov 6 cx mov 1 ax imul cx ax sub 1 cx jnz 2 push ax This program calculates 6!, and leaves the answer (720) on the stack. You should also test your program against instructions that have errors: # stack underflow pop ax # illegal operands for move mov [3] [bx] # illegal destination for idiv idiv ax dx ----------------- Hint: The following function parses a string into an operand that includes "Mem" operands (replace original transoperand): // translate a string x into an operand: let transoperand x = try Imm(int(x)) // try-with block exception handling with | exce -> match x with | "[cx]" -> Mem(Reg("cx")) | _ -> Reg(x);; ================== OPTIONAL CHALLENGE: PEEPHOLE OPTIMIZATION. Write a program that optimizes a (operation list) by replacing redundant code as follows: push ax pop bx --> replace with single instruction mov ax bx push ax pop ax --> eliminate altogether mov ax bx mov bx ax --> mov ax bx