For this assignment, you will write a simulator for the pipelined LC-3b. The simulator will take two input files:
The simulator will execute the input LC-3b program using the control store and the code you write inside the simulator functions to direct the simulation of the datapath and memory components of the LC-3b.
Note: The file isaprogram is the output you generated in 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 ucode is an ASCII file that
consists of 64 rows and 23 columns of zeros and ones.
Similar to the simulator you used in Lab 3, the simulator for this lab is partitioned into two main sections, the shell, which allows a user to control the simulator, and the simulation routines, which carry out the simulation.
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:
Do not change any of the code related to the shell. We will be using these functions to grade your program and our grading script expects the output format provided by these functions.
The simulator simulates one processor cycle via the
function. This function calls the following functions, each of which
corresponds to one of the stages in the pipeline:
SR_stage() function has been written for you to get you started. Your
job is to write the remaining four functions. Note: For each stage,
your code must fully implement the structures in that stage of the
pipeline. Refer to the description of the pipeline, the figures of the
pipeline stages, and the list of control signals to figure out what to
implement in each pipeline stage.
The simulator code provided contains two structures that hold the
state of the pipeline latches:
PS contains the state of
the pipeline latches during the current clock cycle.
NEW_PS contains the new
values of the pipeline latches that will be latched at the end of the
current clock cycle. At the end of each cycle,
NEW_PS is assigned to
PS = NEW_PS) to simulate the latching of data values into the pipeline
registers. You need to make use of these structures while writing the
simulation routines. When you need to read a value from a pipeline
latch, you need to read it from the
PS structure. When you need to
update the value in a pipeline latch, you should update it in the
NEW_PS structure. In other words, the
PS structure should always be used
in the right-hand side of an assignment statement, and the
should always be used on the left-hand side of an assignment
statement. Please carefully examine the code related to these two
structures as you have to use them in the code you write.
We have also provided you with interfaces to the instruction and data
dcache_access functions. You must use these
functions to perform accesses to the I-Cache and the D-Cache.
First, read and understand the documentation for the pipelined version of LC-3b you are going to implement. You may download it from the link below:
Your job is to implement the pipelined LC-3b microarchitecture exactly as it is described in the above documentation. Some of the logic blocks in the pipeline are left for you to implement. It is advisable that you design these logic blocks on paper before you start writing the simulator code.
The shell has been written for you. From your ECE LRC account, copy the following file to your work directory:
At present, the shell reads in the control store and input program and initializes the machine. It is your responsibility to write the correct control store file and to augment the shell with the simulation routines that simulate the activity of the pipelined LC-3b. In particular, you are to write the code to perform the activities of the first four pipeline stages as described above.
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. It is suggested that you start out by writing a one instruction program and simulating the execution of this program cycle by cycle using the idump command to verify that the instruction propagates correctly through the pipeline. We suggest that you start out by making sure a simple instruction, like an ADD, flows correctly through the pipeline. Then you can move on to more complicated instructions like loads and branches. Try instructions one by one to make sure each works as it is supposed to. After you get the memory and control instructions working correctly, you can try more complicated programs that contain dependencies and test whether or not your pipeline stalls correctly.
You are not responsible for implementing the RTI instruction. You are also not required to support exception/interrupt handling, although you are encouraged to think about the issues related to the handling of exceptions and interrupts on a pipelined microarchitecture.
Because we will be evaluating your code in Unix, you must be sure your code compiles on one of the ECE Linux machines using gcc with the -ansi flag and runs correctly. This means that you need to write your code in C such that it conforms to the ANSI C standard. If the value of a control signal is a don't care, you should set that signal to 0. We will be checking the state of the internal pipeline latches and architectural state when testing your simulator. To receive full credit, the values stored in these latches by your simulator should exactly match the values stored in these latches by a correct simulator.
Please submit your lab assignment electronically on grader1. You will submit the following:
For this lab, you may optionally implement support for exceptions and the RTI instruction. Note that implementing these optional additions will receive no extra credit; this is merely for those students who wish to challenge themselves as an additional learning experience. Before implementing exception support into the pipeline, please first complete the basic pipeline functionality.
As a starting point for exception support in the LC-3b pipeline, we recommend making many simplifying assumptions. First, begin with support for only two kinds of exceptions: unknown opcode and unaligned access (LDW/STW only initially). The unknown opcode exception should use exception vector x01, and the unaligned access exception should use exception vector x02.
Assume that all programs will only execute in Supervisor Mode with PSR=0. Thus, no support for two levels of privilege will be required. As a consequence, assume that R6 will always contain the Supervisor Stack Pointer; thus, no switching of stack pointers will be necessary.
Note that both RTI and the steps to initiate the exception handler are complex processes: they each require multiple memory accesses, stack pointer modification, and change in PC. The current LC-3b pipeline resolves control instructions in the MEM stage of the pipeline. Because all exceptions can be detected by this stage, modifying the pipeline to support exceptions will require an additional exception state machine in the MEM stage. We can add additional bits to the MEM stage Pipeline Registers to keep track of whether an exception has been detected, and which state of exception processing the MEM stage is currently carrying out in the case of a detected exception. RTI can be implemented with a similar state machine in the decode stage of the pipeline. These state machines will stall the pipeline until they complete.
To support the stack operations required by the RTI instruction and the exception handler setup steps, it is easiest to assume the MEM stage has access to direct R6 read and write ports from the Register File. Appropriate dependency stall logic will need to be included to wait on previous instructions' potential writes to R6. Similar design principles can be applied to the CC (which need to be saved/restored onto the System Stack as part of the PSR).
Both the RTI instruction and the exception handler setup steps will require additional logic to ensure earlier stages of the pipeline are properly invalidated; this can be implemented similarly to the BR.STALL mechanism used by all control instructions currently in the pipeline. One challenge to consider is that while an RTI can be detected at the same time as other control instructions, memory exceptions cannot be detected until AGEX.
Please contact the TA Faruk for additional details if you wish to implement support for exceptions.