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.
- Download the archived workspace file lab1workspace.zip
- Start Active-HDL 7.1 and cancel out of the "Open Workspace"
- Use Workspace->Restore Workspace to restore the workspace named cse378.
- Open Workspace cse378
- 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.
Part A. ALUCTL
The first test fixture directly controlled the ALU by means of the
signal. The ALUControl component generates these control signals for the
ALU based on the instruction. The decision is made in two parts:
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
opcode input determines the operation.
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
- Add a 2-bit input bus port named
- 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
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
RS for ALU input A.
- Add a multiplexer to choose between
RT for ALU input B.
- Add input ports
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
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
CPUDataIn and the data memory output port
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
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.
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
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
- Connect the output from the PC register to a 32-bit output port named
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:
- In the PCAddressComputer.v file:
- Add code to compute Jump Addresses(Only J instruction, not JAL, JR, or JALR)
- Add code to compute branches:
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.
- BEQ: Branch if RS == RT
- BNE: Branch if RS != RT
- BGTZ: Branch if RS > 0
- BLEZ: Branch if RS <= 0
- 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