CSE141L Lab 2, Part B: Processor Front-End - Fetch Control


CSE 141L Homepage | Lab Overview | Lab Description


Deadlines: Beta Deadline (Q1-Q6): Wednesday, April 20 at 1:45pm PT (via moodle)
Final Deadline (All questions): Wednesday, April 27 at 1:45pm PT (via moodle).
Apr 21 11:59p
    Q11 (now folded into part 3B) has been added.

Lab Overview:

We are making great progress with the fetch unit for our new processor. While we have the datapath all set up, we need to complete our front-end implementation by adding in the necessary control logic. Because our unofficial motto of quality control here at AwesomeCore is "Hugs, not bugs!", you will need to perform some rigorous testing of the completed fetch unit to make sure that it meets our specification. After our work with the front-end is done, we can proceed to the back-end implemenation in the next lab. You must work individually on this lab but make sure you start making friends with your colleagues; you are going to need to find a partner for the next lab. Good luck!

Lab Deliverables:

Again, we won't be requiring that you demonstrate your design to your supervisor. The requirements for this lab are:


Lab Description:

Jump to: Lab Files | Steps: Step 1, Step 2, Step 3, Step 4 | Hints and Tips

Lab Files:

For this lab you do not require additional Verilog files, however we will be performing simulations to test the fetch unit in this lab. As in Lab2a, the required files are in a svn repository. To get the files, do the following in your shell, in the directory you want your files to appear in:

svn checkout svn://parallel.ucsd.edu/fetch-unit-tests/trunk

This will checkout the trunk directory. You can find the testbenchs (*.tfw) files in the trunk/basic directory.

You will probably need to refer to the datapath frequently for this lab.

Step 1: Control Implementation

Now that you have the datapath in place, add all the necessary control logic to fetch.v. To understand the semantics of each control signal, refer to the tables below. Again, part of your grade will count towards your coding style so keep your Verilog code as clean and unambiguous as possible. Since this is control logic that you are writing, you should be using synthesizable RTL verilog or systemverilog to implement it, not structural verilog.

Input Control Signals

The following control signals will come from the back-end of the processor.

Signal Value Semantics
restart_i 0 Normal execution
1 Restart execution from 'restart_addr'
load_store_valid_i 0 No load or store operation
1 Load or store operation.
store_en_i 0 load
1 store

Internal Control Signals

The following control signals are used only within the front-end.

Signal Value Semantics
sel_mux[0] 0 Branch target address (i.e. PC+SignExt(offset))
1 Next instruction (i.e. PC+1)
sel_mux[1] 0 Previously used PC
1 Output of mux0
sel_mux[2] 0 Restart address (i.e. restart_addr)
1 Output of mux1
sel_mux[3] 0 Output of mux2
1 Target address of load or store operation
ram_we 0 Read data from SRAM
1 Write data to SRAM
fifo_enqueue 0 No effect
1 Insert item into FIFO
fifo_clear 0 No effect
1 Remove all entries from the FIFO

Output Control Signals

The following signals are sent to the back-end of the processor.

Signal Value Semantics
instruction_valid_o 0 Data on instruction_addr and instruction_data are invalid
1 instruction_addr and instruction_data are valid
load_data_valid_o 0 load_data is invalid
1 load_data is valid

Step 2: Testbenches

We have provided several testbenches for you to test out the implementation of your fetch unit. As in Lab2a, the required files are in a svn repository. To get the files, do the following in your shell, in the directory you want your files to appear in:

svn checkout svn://parallel.ucsd.edu/fetch-unit-tests/trunk

This will checkout the trunk directory. You can find the testbenchs (*.tfw) files in the trunk/basic directory. You should note that the provided testbenches rely on the following assuptions:
To use the given testbenches, follow the instructions here. You should use the Behavioral simulation for debugging your design. After it is debugged, you run the timing-based simulator to confirm that the final design would actually work in a FPGA at a given frequency.

For the first set of questions (Q1 - Q6), you will need to examine the given files and understand what they are doing. Make sure you pay attention to the time period that each question specifies. You will need to get screen captures of the results of your simulations. You can limit the screen captures to the parts of the simulations that are of interest, but make sure all of the relevent signals are included and that both their names AND values are clearly visible. Failure to produce readable screenshots will result in you not getting any credit for that question.

test.tfw

First, we will be looking at the "test" testbench. Examine the "test.tfw" file and try to understand what functionality is being tested. Now, answer the following questions:

Q1 After the restart is asserted at 200ns, how long does it take for the output signal 'instruction_valid' to change. Show your answer by getting a screen capture of this event.
Q2 How many instructions will the processor back-end have received by 450ns?
Q3 How many load/store operations are executed during the simulation? Do the load/store operations interrupt the transfer of instructions to the back-end? Explain why or why not.
Q4 How many cycles does it take the output port 'load_data_valid' to change after a load operation is asserted? Grab a screen capture to show your answer.

branch.tfw

The "branch" testbench executes the following program:

	addr  instruction
	#0    nonbranch_op0
	#1    nonbranch_op1
	#2    conditional branch to #7 (predicted taken)
	#3    nonbranch_op3
	#4    nonbranch_op4
	#5    nonbranch_op5
	#6    nonbranch_op6
	#7    jump to #0

After examining the tfw file and running the simulation, answer the following questions:

Q5 How many conditional branches were executed in the testbench? How many of these were predicted correctly?
Q6 Explain how the fetch unit recovers from a misprediction. Take a screenshot of your simulation showing the fetch unit during one of the mispredictions.

Step 3: Create a new testbench

An essential skill in hardware debugging is the ability to create your own testbenches. We need you to create a test bench to test the following important situation: both 'restart' and 'load_store_valid' are simultaneously asserted while the FIFO is full. First, try it assuming that the 'dequeue' signal is asserted 2 cycles after 'restart' and 'load_store_valid' are asserted. Why is this not a correct testbench (hint: look at your warning messages)? What is the correct number of cycles? Think it through.

To meet the setup time requirement, you should assert inputs at the negative (i.e. falling) edges, using the @(negedge clk); primitive instead of the #30 notation used in the first two testbenches. This allows your testbench to work even if the clock frequency changes. You should submit your test bench files (*.tfw or *.v) with other Verilog files.

As part of your report, answer the following questions about the test bench you created:

Q7 Fully describe the scenario which you used for your testbench. Make sure you describe when signals are asserted/deasserted and explain why they are changed at those times.
Q8 Show the results of your test bench simulation by taking several screenshots. The screenshots should show all relevant events that occur during your simulation. Of particular concern are the transitions on the output signals (namely, fifo_full, instruction_valid and load_data_valid).

Step 3B: Rock the automatic testbench infrastructure

Often times, we verify hardware through the use of a C++ simulator that we compare against the Verilog. In this case, we have created the C++ simulator, and provided a set of testbench inputs/outputs pairs that have been generated by the simulator. When you have a mismatch between your C++ simulator and your RTL on a test, it will fall into 4 categories:
  1. bug in your verilog,
  2. bug in the testbench inputs,
  3. bug in the simulator,
  4. or, doesn't matter (i.e. behavior is undefined for the set of inputs)
Part of the exercise is to figure out what the design should do for that set of inputs, and/or if it is well defined what should happen. Then you can determine which category it falls into.

Q11 Use the provided testbenches to attain correctness of your design. Details about finding and using the files can be found here. This question has 2 parts:

a. For each of the testbench (*.tfw) provided, look at the input signals and the data/address values being given (you should take a look at the *.in files) and briefly describe what is the operation being performed.

b. Compare your results with the given *.chk files. In your report, show the mismatches between your *.out file and given *.chk file, and explain the bug that caused it, and how you fixed it. Or if it is not a bug, explain why. You can provide a 'vimdiff' image or a similar mechanism to highlight differences, but make sure that it is clear and easily readable.

Step 4: Performance Evaluation

Now that we are confident that the fetch unit is operating correctly, it is time to see how we are doing with performance. As you did in Lab 1, you will evaluate performance using the TimeQuest timing analyzer that is generated by Quartus II.

Implement your design now and look over the timing report that has been generated.

Q9 What is the maximum achievable frequency?. If the branch prediction is perfect, what is the maximum number of instructions your fetch unit transfers to the backend in 1 second?

Note that the "critical path" is the path through your processor with the longest delay. Decreasing the length of the critical path would allow you to increase the frequency of your processor.

Q10 Based on your timing report, describe the critical path in your fetch unit. For example, the critical path might be: load_store_addr_r -> mux3 -> sram.addr

Hints and Tips

The following information may help you with this lab.