MIPS Assembly stalls and forwarding when a register's value isn't modified in previous step

Sonar87

n00b
Joined
Sep 22, 2017
Messages
7
I'm going over pipelining and stalls and forwards with MIPS architecture, and there's a couple things I'm uncertain about.

If two adjacent instructions, such as the first two of each set bellow, both use the same register, but the first isn't actually modifying that register, is there still a stall? Like if the add and first addi of the second set each modified $t0, then yea, you'd want a stall because you'd want the updated $t0 value to be used in the next instruction. But here the result of the next instruction wouldn't actually be affected since $t0 doesn't change. So is there no stall in this case? Or is there a stall just because the register is in use despite whether or not it's being written to or only read?

And in the first set is the first addi between the add and second addi enough of a gap not to need a stall over $t1's use? Or would you stall need forwarding to help there?

--------------------------

add $t1, $t0, $t0
addi $t2, $t0, 1
addi $t3, $t1, 1

--------------------------


addi $t1, $t0, 1
addi $t2, $t0, 2
addi $t3, $t0, 3

--------------------------
 
In general, this will highly depend on the number of pipelines stages in the architecture. However, your example is pretty straightforward for a 5-stage pipeline MIPS architecture. By the time that the $t0 result (from 1st instruction) is ready (at the end of the Execute stage) the next instruction has been decoded and ready for Execution. Through value forwarding, the $t0 result from the 1st instruction can/will be muxed as the input to the 2nd instruction's Execution stage. Thus, a pipeline bubble (i.e. stall) will not be necessary between those two instructions. This is an easy enough example for me to visualize in my head.

That said, I find it easier to draw each pipeline stage (on paper) and note their inputs and outputs at each stage. It's easier to visualize things as they progress through the pipeline. It's also easier to spot such hazards through visualization. Then again, I'm no assembly wizard with a photographic memory.

Edit: Whoops. Oh how we forget things... what's the saying...? You don't use it? You lose it. It's been a while since I've looked at MIPS assembly, so forgive me. I got the add instruction arguments backwards. $t0 is not the desination register for the 1st instruction, $t1 is. So in the first set the only potential hazard is between 1st instruction and 3rd instruction. My answer still applies, but the value forwarding part isn't necessary as the 1st instruction will have already written to the destination register by the time the 3rd instruction needs it. So this example (as-is) is even more trivial in that it needs no special handling as there are no hazards.

Make the 1st instruction's destination argument $t0 (i.e. add $t0, $t0, $t1) and you end up with a hazard per my initial response.
 
Last edited:
"So in the first set the only potential hazard is between 1st instruction and 3rd instruction. My answer still applies, but the value forwarding part isn't necessary as the 1st instruction will have already written to the destination register by the time the 3rd instruction needs it."

Wait... what stages are the writing to the register in the add and use of $t1 in the addi?

upload_2017-12-3_22-23-13.png


I thought it write to $t1 in the WB and the be needed by the last addi in the EX, which would mean it's needed at the same time it's being written to, seeming like it does need forwarding.
 
The output of stage MEM (1st) should be fed into the input of stage EX (3rd). I was incorrect in my assertion that there isn't a hazard at all. Technically, there is a hazard as Write Back (1st) hasn't finished by the time 3rd instruction EX stage needs it. So value forwarding is quite necessary for $t1.

upload_2017-12-4_1-22-46.png


Although... writing to registers is generally fast and doesn't really need the entire MEM stage. But because data fetch always has to come from memory, this stage (MEM) is necessary from a hardware standpoint. For ADD or any other register to register instruction, the ALU result is clocked through the MEM stage until Write Back happens. The output of the ALU is considered "stable" for these particular instructions. Loads (LW) would be the case where a "stable" result will not happen until after the MEM stage.

Basically, the value of $t1 (1st) is considered "stable" at the output of the EX stage through the WB stage. Again, this has more to do with the property of the ADD instruction itself (register to register). Knowing that, you can then mux the outputs of EX or MEM (1st) to the inputs of the the other future stages in the pipeline. The important part here is "future". You forward outputs/values to inputs of future stages.
 
Last edited:
Back
Top