A pipelined processor overlaps instructions the way an assembly line overlaps cars. In the classic 5-stage design each instruction passes through IF (fetch), ID (decode and read registers), EX (execute), MEM (memory access) and WB (write back). Once the pipeline is full, ideally one instruction finishes every cycle, so CPI = 1.
Data hazards and forwarding
When an instruction needs a result that an earlier instruction has not written back yet, that is a read-after-write hazard. Forwarding sends the value straight from the EX/MEM or MEM/WB pipeline register into the ALU input, so back-to-back dependent ALU instructions run without waiting. Without forwarding, the dependent instruction waits in ID until the result is written back, which costs up to two cycles.
The load-use stall
A load's data only exists at the end of MEM. The next instruction needs it at the start of EX, one cycle earlier, so even with forwarding the pipeline inserts one bubble. Compilers hide this by scheduling an independent instruction between the load and its use.
Control hazards
Branches resolve in EX. Pick a branch predictor (always not taken, always taken, backward-taken/forward-not-taken, 1-bit or 2-bit counters): when the guess is wrong, the two instructions fetched after the branch are flushed, costing 2 cycles, and a correct guess costs nothing. jal knows its target in ID (1 flushed fetch), and jalr, for example ret, needs a register, so it resolves in EX (2 flushed fetches).
Counting cycles
Total cycles = instructions + 4 to fill the pipeline + stall cycles + flush cycles. Example: lw a0,0(t0) followed by add a1,a0,a0 costs one extra cycle. Toggle forwarding to see how many cycles it saves on your own code.