CSE141L Lab 2, Part A: Processor Front-End - Fetch Datapath


CSE 141L Homepage | Lab Overview | Lab Description


Deadline: Oct. 17 at Noon.
Changes:
  1. Oct. 15, 2:30PM: There is an error in the fetch.v file. Line 64 of this file should read .deque(dequeue) (note the extra 'ue' added inside of the parentheses).
  2. Oct. 15, 2PM: Made a couple clarifications to Q5. In cycle 1, the fifo_full signal goes to 1. In cycle 7, removed the statement about fifo_full becoming 0 because it did not make sense in context of the earlier restart.
  3. Oct. 15, 2PM: Added a note to the description of the fetch unit to specify that the FIFO should be cleared after a restart.

Lab Overview:

Now that you are comfortable with using our design tools, it is time to get down to the business of creating our new microprocessor. Here at AwesomeCore, we split our processor design into two parts: the front-end and the back-end. We'll need more time to strategize and decide on the back-end design so we'll start with the design of the front-end (or fetch unit). Luckily for us, the front- and back- ends are mostly independent so we can immediately start on designing and implementing the fetch unit. In this lab we'll implement the datapath for the fetch unit, saving the control logic for next lab. As was the case with lab 1, you should work alone on this lab. Good luck!

Lab Deliverables:

Because we are giving you the specification for fetch unit datapath, we won't be requiring you to give a demonstration at the end of this lab. The requirements for this lab are:


Lab Description:

Jump to: Lab Files | Fetch Unit Specification | Datapath Implementation

Lab Files:

Start by downloading the following zip file:
cse141L-lab2-part_a.zip.

Note: You will frequently need to reference datapath.pdf from the ZIP file so we have provided a link to it directly from here.

The zip file contains the following files:

File Description
ram17_1024.v Behavioral Verilog file that describes a RAM with 1024 addresses, each containing 17 bits of data. It should only be used for simulations and is not synthesizable.
fifo27_16.v Behavioral Verilog files for a 16 entry FIFO queue with 27 bits of data in each entry. Again, it is only for simulations and is not synthesizable.
fifo.v A wrapper for the FIFO queue that more clearly conveys the semantics of a FIFO. (For the datapath, you do not need to understand the semantics of the FIFO. It will be discussed in more detail when you need to implement control.) Internally it uses the fifo27_16 FIFO so you need both these modules in your Xilinx project. Like fifo27_16.v, it is not synthesizable.
ram17_1024.ngc Implementation file for the RAM module. Place this in your project directory and Xilinx will use it for synthesis and implemenation.
fifo27-16.ngc Implementation file for the FIFO module. Place this in your project directory and Xilinx will use it for synthesis and implemenation.
ram17_1024.mif A file that specifies the contents of the RAM. Addresses 0x00 - 0x3f (i.e. 0 - 63) contain their own address (e.g. address 5 have "5" stored in it) while all other addresses (i.e. 64 - 1023) have the value "0" stored in them.
adder.v 2-input 32-bit adder verilog module. You must complete the implementation of this module.
fetch.v Verilog module for fetch unit. You must complete the implementation of this module.
mux.v Verilog module for 2-input multiplexor. You must complete the implementation of this module.
signext.v Verilog module for sign extension unit. You must complete the implementation of this module.
datapath.pdf Schematic of the fetch unit's datapath.

Create a new project in Xilinx and add all the Verilog files from the zip file to it. As in lab 1, we will be targetting the "Virtex 4 - XC4VLX15" FPGA for our design. Make sure the NGC and MIF files are in your project directory or Xilinx might cry.

Fetch Unit Specification

The following code (from the fetch.v file) gives the interface for your fetch unit:

module fetch#(parameter I_WIDTH = 17, A_WIDTH = 10, O_WIDTH = 5)
(
	input	clk,

	// inputs from the exec unit
	input	dequeue,
	input	restart,
	input	[A_WIDTH-1 : 0]	restart_addr,

	// memory interface
	input	load_store_valid,
	input	store_en, 
	input	[A_WIDTH-1 : 0] load_store_addr,    
	input	[I_WIDTH-1 : 0]  store_data,        
	output	[I_WIDTH-1 : 0]  load_data,
	output	load_data_valid,

	// ouputs to the exec unit    
	output	[I_WIDTH-1 : 0]	instruction_data,
	output	[A_WIDTH-1 : 0]	instruction_addr,
	output	instruction_valid
);

Your fetch unit must obey the specification that follows:
  1. An instruction contains 17 bits. The most significant bit (MSB) is the 'P' (or "prediction") bit. If the 'P' bit is set to '0' then the instruction is either: a) not a branch or b) is a branch that has been predicted as 'not taken.' The 5 least significant bits (LSBs) of the instruction are the 'offset' bits for branch instructions. We will use these 'offset' bits to calculate the branch target according to the following formula: target = PC + SignExt(offset). SignExt(offset) is simply the sign extended version of the offset. Note: The offset is given in 2's complement and therefore may contain a negative number. You do not have to worry about the other 11 bits of the instruction for this lab.
  2. SRAM has 1024 (i.e. 1K) addresses and therefore uses 10 bits for addressing. Each address contains 17 bits of data. We have provided files for simulating (ram17_1024.v) and implementing (ram17_1024.ngc) the SRAM. The implementation of the SRAM was created using coregen, a utility from Xilinx, and is highly optimized. Please read the description of the file above to learn about what each address is initialized to in the SRAM.
  3. The FIFO queue has 16 entries, each holding 27 bits of data. The entries of the FIFO are broken into two parts: 1) the address (10 bits) and 2) the instruction (17 bits). It is also a highly optimized implementation that was created by the coregen utility.
  4. In order to allow the program counter (PC) to restart at an arbitrary address, 'restart' and 'restart_addr' are provided as inputs to the fetch unit. If 'restart' is set to '1' then the PC will change to the address specified by 'restart_addr' and the FIFO will be cleared. Using this mechanism, we can reset the fetch unit by setting 'restart' to '1' and setting 'restart_addr' to '0x0.' This will cause the fetch unit to start fetching instructions at address '0'.
  5. To allow reading and writing to the SRAM, the fetch unit supports "load" and "store" instructions. Two inputs to the fetch unit, 'load_store_valid' and 'store_en', fully specify load and store instructions. When 'load_store_valid' is set to '1', the fetch unit know the instruction is a load or store. Setting 'store_en' to '1' further specifies the instruction as a store (conversely, a '0' value on 'store_en' implies a load). For load instructions, the fetch unit produces a 17-bit instruction on the 'load_data' output. In the case of a store, the fetch unit writes 'store_data' into the address specified by 'store_addr'.
  6. Load and store instruuctions have a higher priority than other fetch unit operations, including restart. These memory operations receive higher priority because the processor back-end may be dependent on their timely execution.

Datapath Implemenation

Now that you have the specification for the fetch unit, you need to think about implementing it. Before doing so, you need to take the time to thoroughly understand the specification; we don't want to have any bugs holding us up when we move on to creating the back-end. You should answer the following questions in order to make sure we have all of our bases covered. In the process answering these questions, you will be able to implement the Verilog modules that are needed for a functioning fetch unit datapath. Remember that your answers should be complete but concise. Note: For all questions other than Q5, you should assume that the FIFO never fills up.

Q1 Suppose that the address of the last fetched instruction (pc_prev_r) is 0x12. If the 'P' bit of the last fetched instruction is '0', what is the address of the next fetched instruction? Assume that restart signal is not asserted.

The situation described in Q1 requires the use of an adder and MUX. Implement both of these components in Verilog in their respective files (adder.v and mux.v). Make sure you use RTL Verilog.

Q2 What is the binary encoding of an instruction that branches to the instruction located right before the current instruction? For example, if the current instruction is 0x25, it should branch to 0x24. Use 'X' for don't care bits. Briefly explain how this case would be handled in the given datapath.

As mentioned earlier, the calculating the branch target requires the sign extended version of the offset. Implement the sign extension module in signext.v so that branches can function correctly. Hint: You can duplicate a bit N times by {N{1'bx}} in verilog. For example, 5'b11111 can be briefly expressed by {5{1'b1}}. )

Q3 Imagine the following scenario. The back-end execution unit has found that the branch prediction in the fetch unit was wrong. How can it generate the correct address for the fetch unit? If the execution unit sent 'restart' and 'restart_addr' at cycle 10, what is the earliest cycle in which the execution unit can start executing at correct address? Explain.
Q4 Examine the datapath. Notice that 'pc_prev_r' can be used for the 'pc' and can be fed to the SRAM. Considering that 'pc_prev_r' saves the "previous pc", it seems odd to use the same address in two consecutive cycles. Explain why this path is needed.
Q5 Envision the following scenario.
  • Cycle 0: An instruction 0x10003 with address 0x10 is fed to the FIFO. (assume that sel_mux[2] is 1 at cycle 0.)
  • Cycle 1: No external input is asserted. However, fifo_full becomes 1 as a result of inserting instruction 0x10 into the FIFO.
  • Cycle 2: load_store_valid is asserted with {store_en=0, load_store_addr = 0x40}. 'restart' signal is not asserted.
  • Cycle 3: No external input is asserted.
  • Cycle 4: The following signals are asserted - {restart = 1, restart_addr = 0x0, load_store_valid = 1, store_en = 0, load_addr = 0x50}.
  • Cycle 5: No external input is asserted.
  • Cycle 6: 'dequeue' signal is asserted.
  • Cycle 7: No external input is asserted. Assume that the 'p' bit of the instruction at 0x0 is 0.
List all the address values fed to the address port of the SRAM from cycle 0 to cycle 7 with explaination.

You should now be ready to implement your fetch unit in Verilog (fetch.v). In doing so, you should follow these simple guidelines:

  1. Use structural verilog, not a behavioral verilog or RTL verilog. You should instantiate mux, adder, and signext modules in the fetch.v file. The FIFO and RAM have already been instantiated in fetch.v for you..
  2. Use non-blocking assignments (i.e. <=) for flip-flops.
  3. Where applicable, always use signal names in the provided datapath schematic. Otherwise, use consistent and readable naming style. The naming convention, proper indentation, and style will be graded. Make sure your Verilog file is readable in the Xilinx ISE editor.
  4. Your Verilog modules should be both synthesizable and implementable in Xilinx ISE.
Don't forget to include all your files in the ZIP file you will be submitting to Sat.

Q6 Given that you have not implemented control signals yet, why does it make sense that there is no frequency check question for this lab?

Good luck!


This lab created by Donghwan Jeon, 2007. Modified by Sat Garcia, 2008.