Hazards
A hazard is a situation where the next instruction cannot run in the next cycle. The pipeline has three kinds, and the core handles each one differently. The app's hazard lab runs each kind on the pipeline with forwarding on and off, and on the single-cycle core, so you can see the cost.
Data hazards: a value is not ready yet
If an instruction reads a register that the instruction just before it is still computing, the value does not exist yet in the register file. The pipeline has two options.
- Forwarding: take the value from the EX/MEM or MEM/WB pipeline register, where it already is, and pass it straight into EX. With forwarding, an ALU result can be used by the very next instruction with no delay. Without it, the pipeline must wait.
- Stalling: hold the dependent instruction in ID for a cycle. The hazard lab's "ALU to ALU, distance 1" case shows the difference: forwarding removes the stall.
Load-use: the one case forwarding cannot fix
A load returns its value at the end of the MEM stage, which is later than the EX stage that needs it. Even with
forwarding, the next instruction must wait one cycle. This is the only stall the core takes with forwarding on.
Step through this program and find the cycle where the dependent addi waits.
Loading the core…
Control hazards: a branch changes the path
A branch decides whether to jump in EX, but two instructions behind it have already been fetched. The core predicts that a branch is not taken, so it keeps fetching in order. If the branch is taken, those two instructions are discarded: a taken branch costs two cycles, with or without forwarding. A branch that is not taken costs nothing.
Measured, not assumed
Each claim on this page is a test. The Vitest suite runs every hazard case on the WASM module and checks the cycle counts: the distance-1 stall disappears with forwarding, the load-use case stalls exactly once, the taken branch costs the same with and without forwarding, and the independent case is the same either way.