CSE logo University of Washington Department of Computer Science & Engineering
 CSE 378, Winter 2007
 Machine Organization and Assembly Language Programming
  CSE Home  About Us    Search    Contact Info 

 Academic (Mis)Conduct
 Course wiki
 Mailing list
 Lectures and readings
 Lab hours
 Your Grades
Anonymous Feedback
 Submit Feedback
 Read Feedback
Printable view

Lab 1: Introduction to the Datapath - SW

Out: Monday, 1/29/07
Due: Tuesday, 2/6/07


This first lab will give you a chance to (re)learn Active-HDL while constructing the datapath and some of the control components your processor will need. We will provide a minimal datapath and necessary components. Your task is to augment the datapath to support a wider range of capabilities.


In CSE 370, the labs focused on the design and implementation of special-purpose circuits, which are designed to fulfill one specific role, e.g. a universal shift register or a magnetic card reader. In contrast to special-purpose circuits, there are general-purpose circuits that can be put to a variety of uses. In CSE 378, you will be designing a relatively simple version of possibly the best-known general-purpose circuit, the microprocessor. As discussed in lecture, one logical and common breakdown of a processor is the datapath vs. the control. The datapath is, along with state elements such as the register file and the program counter, simply the route by which data makes its way through the processor, whereas the control modifies various aspects of the processor's behavior based on its state. In short, the control may be considered the "brains" and the datapath the "brawns" of a processor.

In this writeup, there are several formatting conventions that are being used to help you distinguish between types of items in your design more easily. Code font indicates wire and input/output port names while italic font indicates a component that you will need to add from lib378. Addtionally, should you require basic components to use in your processor, such as muxes, you should get them from lib378 if possible.

One important convention that will be important in this section is the naming of the mux components. Each mux component has a name in the format mXw_Y_1_D where X represents the width of the mux (32, 6, 5, or variable - indicated by V - bits), Y represents the number of inputs that the mux can select between (2 or 4), and D represents where the selection port is on the mux (top or bottom). As an example, the component "m32_4_1_top" represents a 32-bit wide mux with 4 inputs that it can select between and a selection port on the bottom.

It is also VERY important that you follow the instructions when it comes to naming your wires. They must be named exactly as specified in this writeup with the correct case for characters. If you do not follow the naming conventions, the test fixtures will not function properly.

Phase 1: Using test-fixtures

The original datapath contains only a register file for storage, and an ALU or arithmetic logic unit which performs all the computation. With only these components, a number of instructions can be computed. The test fixture will demonstrate this by running through a large number of operations.

  1. Download the archived workspace file lab1workspace.zip
  2. Start Active-HDL 7.1 and cancel out of the "Open Workspace" wizard
  3. Use Workspace->Restore Workspace to restore the workspace named cse378.
  4. Open Workspace cse378
  5. Right-click on Tests/phase1_runtest.do and select "Execute"

The simulation should display a series of messages in the console window that list and operation followed by the success or failure of that operation. Verify that all of the operations complete successfully before continuing.

Phase 2: Immediates and Shifting

Small constant values are used frequently in programs for initializing values, address calculations, iteration and other purposes. To save space in the register file, the MIPS instruction set allows small constants to be included in the instruction itself. A constant specified this way is called an immediate because its value is consumed immediately, and isn't available to later instructions in the general case. Consequently, for many simple register operations such as ADD, there are immediate versions. Your next task is to extend datapath.bde to implement the MIPS immediate instructions.


The first test fixture directly controlled the ALU by means of the ALUCtl signal.  The ALUControl component generates these control signals for the ALU based on the instruction. The decision is made in two parts:

  1. The ALUControl takes a two-bit ALUOp that determines the mode of ALUCtl: Add, Subtract, R-Format, or I-Format. The first two are self explanatory, while the last two tell the ALUControl whether its 6-bit func or opcode input determines the operation.
  2. In R-Format mode, the func field of the instruction (bits 5:0) determines the operation. In the I-Format mode, the opcode field of the instruction (bits 31:26) is used.

Your tasks for Part A are the following:

  • Replace the ALUCtl input port (NOT the port on the ALU) with an ALUOp(1:0) input bus port
  • Add an ALUControl symbol to the datapath.
  • Connect up all ports on the ALUControl appropriately

Part B.  Extensions

The immediate field in the MIPS immediate instructions is 16 bits wide, whereas the ALU performs its operations on 32-bit values. Therefore, the 16-bit immediate field must be widened to 32 bits while maintaining the same value in order for immediate instructions to produce correct results. For twos-complement binary values, the correct method for accomplishing this task is known as sign extension, which consists of filling in the new high-order bits with the msb of the original narrower value. For example, sign-extending 10 to 4 bits would result in 1110, and sign-extending 01 to 4 bits would result in 0001. This is the case for the arithmetic I-format instructions. However, the logical I-format instructions require zero-extended immediates, and LUI requires left-aligned immediates.

  • Add a 2-bit input bus port named ExtOp
  • Add and appropriately wire up an Extender. Name the output wire ExtImmed. This wire will be used in the next part of this lab.

Part C.  Computing with Immediates and Shifting

The extender processes the 16-bit immediate according to the ExtOp control signal but it still needs to be passed to the ALU. To make sure that immediate and shift instructions work, we need to pass the new immediate into the A and B inputs of the ALU. So we need to add multiplexers to choose between the values from the register file and the output from the extender.

  • Add a multiplexer to choose between ExtImmed and RS for ALU input A.
  • Add a multiplexer to choose between ExtImmed and RT for ALU input B.
  • Add input ports SrcASel, SrcBSel that control the appropriate multiplexers.
  • Wire up the new parts so that a select input of 0 selects the register -- the test fixture will assume this convention.

Part D. Testing the changes

Test the updated Datapath.bde with test fixture phase2_tf.v, and macro phase2_runtest.do. If there are any errors, you may want to see the source code for the test (phase2.s).

Phase 3: Memory Operations

So far, the datapath supports register and immediate operations. However, a processor whose storage is limited to the on-board registers is a very sad processor indeed. To remedy this situation, the MIPS instruction set specifies two basic classes of operations that interface with main memory, loads and stores. Load instructions cause the value in a memory location to be transferred to a register, and stores transfer the value in a register to a memory location. You will next add hardware to implement loads and stores.

Part A. Adding Memory Ports

For the duration of Lab 1, the memories will be separate from the datapath and will be accessible by ports instead. Interfacing with the data memory will require an input and an output for the data and an output for the address. The instruction memory will require an output for the address and will continue using the instruction input. Note that the instruction memory input Inst and data memory address outputs ALUOut are already present. All ports to be added in this part will be 32 bits wide. Name the data memory input port CPUDataIn and the data memory output port CPUDataOut.

Part B. Storing to Memory (SW, SB, SH )

There are three main store instructions: SW,SB, and SH. The S stands for store, and the other letter represents the size of the data to store: W - word (4 bytes), H - halfword (2 bytes), and B - byte (1 byte).

Connect the appropriate ports. In the case of SB and SH, the controller and memory system will take care of selecting the correct bits, so do not attempt to select or otherwise alter the memory-bound bits. In short, always send a full unaltered word to data memory.

Part C. Reading from Memory ( LW, LB, LH )

  • Add a multiplexer to select whether to write the (ALU output) or (data memory output) to the register file.
  • Add a input port for the multiplexer's select input named Load. An input of 0 should cause the ALU output to be chosen.
  • Wire things up appropriately and connect ports as necessary.
  • Note: As with stores, the controller and memory system will take care of choosing the correct bits, so you are encouraged not to alter the incoming data from memory.

Part D. Testing your Changes

Test the updated Datapath.bde with test fixture phase3_tf.v, and macro phase3_runtest.do. If there are any errors, you may want to see the source code for the test (phase3.s).

Phase 4: Control Flow

The program counter (PC) is a register whose value corresponds to the address of the current instruction in the instruction memory. In addition to the PC itself, the processor requires hardware to calculate the next value of PC, which is simply PC+4 unless otherwise specified in an instruction. The next task is to implement the PC as well as the PC-updating hardware.

Part A. Standard Path (PC += 4)

  • Add a PC register (use a register provided in lib378 with a reset input)
  • Add an Adder
  • Add a constant and set to 4
  • Connect it all up
  • Add an input port named RESET and connect it to a global wire (Just like CLK)
  • Connect the output from the PC register to a 32-bit output port named PCOut

Part B.  Jumps and Branches

There are two basic classes of instructions that cause program execution to deviate from the "normal" sequential pattern. Jumps cause the processor to execute an instruction at an absolute location, whereas branches cause the processor to execute an instruction relative to the current value of PC+4. In the MIPS instruction set, jumps are unconditional, where as branches are conditional.

For this part you will fill in the details of the PCAddressComputer module in the following way:

  • Add the following 1-bit inputs: Branch, JAL, JR, and Jump.
  • In the PCAddressComputer.v file:
    • Add code to compute Jump Addresses(Only J instruction, not JAL, JR, or JALR)
    • Add code to compute branches:
      • BEQ: Branch if RS == RT
      • BNE: Branch if RS != RT
      • BGTZ: Branch if RS > 0
      • BLEZ: Branch if RS <= 0
      The upper 4 bits of all of these opcodes are 0001, only the lower 2 differ bits and are defined in the skeleton file for you.
  • Wire up your PCAddressComputer

Part C. Testing

Test the updated Datapath.bde with test fixture phase4_tf.v, and macro phase4_runtest.do. If there are any errors, you may want to see the source code for the test (phase4.s).


To turn in your lab, complete all phases and use the Design -> Archive Design command in ActiveHDL on the final product to produce a .zip file containing all the essential files. Put this somewhere accessible via attu and use "turnin -c cse378 'your file'" to submit it for grading.

Creative Commons License
This work is licensed under a Creative Commons Attribution-Share Alike 2.5 License.
Department of Computer Science & Engineering
University of Washington
Box 352350
Seattle, WA  98195-2350
(206) 543-1695 voice, (206) 543-2969 FAX
[comments to zahorjan]