For this assignment, you will write a cycle-level simulator for the LC-3b. The simulator will take two input files:
The simulator will execute the input LC-3b program, using the microcode to direct the simulation of the microsequencer, datapath, and memory components of the LC-3b.
Note: The file isaprogram is the output file from Lab
Assignment 1. This file should consist of 4 hex characters per
line. Each line of 4 hex characters should be prefixed with '0x'.
For example, the instruction NOT R1, R6
would have
been assembled to 1001001110111111
. This instruction
would be represented in the isaprogram file as 0x93BF
.
The file ucode3 is an ASCII file that consists of 64
rows and 35 columns of zeros and ones.
The simulator is partitioned into two main sections: the shell and the simulation routines. We are providing you with the shell. Your job is to write the simulation routines.
The purpose of the shell is to provide the user with commands to control the execution of the simulator. In order to extract information from the simulator, a file named dumpsim will be created to hold information requested from the simulator. The shell supports the following commands:
The simulation routines carry out the cycle-by-cycle simulation of the input LC-3b program. The simulation of any cycle is based on the contents of the current latches in the system. The simulation consists of two concurrently executing phases:
The microsequencer phase uses 9 bits from the microinstruction
register and appropriate literals from the datapath to determine
the next microinstruction. Function eval_micro_sequencer
evaluates this phase.
The datapath phase uses 26 bits of the microinstruction to
manipulate the data in the datapath. Each microinstruction must be
literally interpreted. For example, if the GateMDR
bit is asserted, then data must go from the MDR onto the bus. You
must also establish an order for events to occur during a machine
cycle. For example, data should be gated onto the bus first, and
loaded into a register at the end of the cycle. Simulate these
events by writing the code for functions eval_bus_drivers
,
drive_bus
and latch_datapath_values
.
We will assume a memory operation takes five cycles to complete.
That is, the ready bit is asserted at the end of the fourth cycle.
Function cycle_memory
emulates memory.
The shell has been written for you. Copy the following file to your work directory:
lc3bsim3.c
At present, the shell reads in the microcode and input program
and initializes the machine. It is your responsibility to write
the correct microcode file and to complete the simulation routines
that simulate the activity of the LC-3b microarchitecture. In
particular, you will be writing the five functions described above
(eval_micro_sequencer
, cycle_memory
, eval_bus_drivers
,
drive_bus
, and latch_datapath_values
).
Add your code to the end of the shell code. Do not modify the shell code.
The accuracy of your simulator is your main priority. Specifically, make sure the correct microarchitectural structures sample the correct signals.
It is your responsibility to verify that your simulator is working correctly. You should write programs using all of the LC-3b instructions and execute them one cycle at a time (run 1). You can use the rdump and mdump commands to verify that the state of the machine is updated correctly after the execution of each cycle.
Because we will be evaluating your code on linux, you must be sure your code compiles on an ECE linux machine using gcc with the -ansi flag. This means that you need to write your code in C such that it conforms to the ANSI C standard. You should also make sure that your code runs correctly on one of the ECE linux machines.
You will submit the following files:
Please make sure that you have made the following correction to the ISA handout.
In Appendix A, please correct the operation of the JSR/JSRR instruction to read:
TEMP = PC†
if (bit(11)==0)
PC = BaseR;
else
PC = PC† + LSHF(SEXT(PCoffset11), 1);
R7 = TEMP;
* PC†: incremented PC
Please note that LEA does NOT set condition codes.
LC-3b registers are 16 bits wide. However, when you perform
arithmetic or bitwise operations in C on int
data types on the Linux x86 machines you are using 32 bits.
Therefore, you must be careful about not keeping the higher 16
bits of the results in the architectural state. The shell code
includes a macro called Low16bits
that you can
use to avoid this problem.
The control signals in your ucode3 file must be encoded according to Tables C.1 and C.2 in Appendix C. For each signal, the first (leftmost or the topmost) signal value must be encoded as 0, the next value as 1, the value after that as 2 (binary 10) and so on. For example, Table C.1 lists the signal values for the two bit signal ALUK as follows: ADD, AND, XOR, PASSA. This means that ADD must be encoded as binary 00, AND as 01, XOR as 10, and PASSA as 11. Please use a 0 whenever a particular signal is a don't care.