In this lab, you will add pipelining to your datapath from the previous lab. You are welcome to use your own datapath if you are more comfortable, but I have a completed datapath that includes some useful subcircuits that you may want to start with. I will give you instructions on how to access the completed datapath implementation at the start of class.
First, we need to identify the five pipeline stages of our datapath. These are:
We will need four pipeline registers: IF/ID, ID/EX, EX/MEM, and MEM/WB. It would be a bit of a hassle to make a separate subcircuit for each, so instead, use the provided pipeline register subcircuits to pass values between stages. The provided subcircuits include all four sizes of registers you should need: 1 bit, 2 bits, 8 bits, and 32 bits.
Use these pipeline registers to separate each stage of the pipeline. Pay close attention to wires that move from the right side of the datapath to the left side; these operations should be associated with instructions as they pass through the pipeline, even though their wires may not cross the entire circuit in the single-cycle implementation.
Now that we’ve built a pipelined datapath, we can test it with some useful programs. Of course we don’t have any special circuitry to avoid data and control hazards, so you have to be careful.
Encode the simple test program from class on Monday, where we add 1 to a register five times in a row.
If you do not add nop
s between the addi
instructions, what value do you get at the end of the execution?
What is the smallest number of nop
s you must add for your pipeline to produce the correct answer?
Submit the assembly and machine code programs, both with and without nop
s.
Write a program that counts up by powers of two in a loop, storing the result in $r0
each time. Add nop
instructions as needed to avoid data and control hazards. Submit your assembly program and an encoded version.
Recall that the Fibonacci sequence has a nice recursive definition: , where and .
Write and encode an assembly program that computes and puts the result in the register $r0
.
You may assume the value of is initially in register $r3
.
When the procedure is finished, send the processor into an infinite loop.
Watch out for data and control hazards!
Hint: you may want to write some start-up code that loads a small test value into $r3
before starting your main code.
Hint: our architecture does not have an indirect jump, so there is no way to return from a recursive call. You will have to use an iterative implementation of fib for this architecture.