This page is one big practice arena for the ideas in the parent note . We will not learn any new theory here — instead we take the three formulas the parent built (pipeline cycles, superscalar IPC, interrupt latency) and push them into every corner case that a real embedded engineer meets: tiny inputs, huge inputs, the "trap" answer, the degenerate answer, the word problem, and the exam twist.
Before any example, let us re-state the three tools in plain words so nothing appears unearned.
Recall The three formulas we will reuse (from the parent)
1. Pipeline cycles. An N -stage pipeline is an assembly line with N work-stations. The first instruction must walk through all N stations before it finishes; every instruction after it finishes just one clock later. So for I instructions:
Cycles = ( N − 1 ) + I
The ( N − 1 ) is the one-time "fill the pipe" tax.
2. Superscalar IPC. IPC = Instructions Per Cycle . A normal core finishes 1 per cycle (IPC = 1 ). A dual-issue core (like M7) can start 2 at once, but only when a pair of instructions is independent enough. If a fraction p of pairs can go together, and the machine is w -wide:
IPC = 1 + p ( w − 1 )
3. Interrupt latency. When an interrupt fires, the CPU must (a) notice it, (b) stack 8 registers, and (c) wait if something more urgent is already running:
L m a x = t detect + t stack + t higher-prio busy
Every symbol above (N , I , w , p , L m a x ) is now defined. Good — let us build the map of cases.
Think of every problem this topic throws as landing in one cell . If we solve one example per cell, the reader never meets an unseen scenario.
#
Case class
What makes it tricky
Example that hits it
A
Single pass, small I
Fill tax dominates
Ex 1
B
Many passes, large I
Fill tax becomes negligible
Ex 2
C
Degenerate: I = 0 or I = 1
Formula must still make sense
Ex 3
D
Limiting: I → ∞
Average cycles/instr → 1
Ex 3
E
Superscalar, p = 0 vs p = 1
The two extremes of dual-issue
Ex 4
F
Superscalar realistic p
Fractional, real-world value
Ex 4
G
Interrupt latency, no blocking
Best case (t busy = 0 )
Ex 5
H
Interrupt latency, nested/blocked
Worst case, higher-prio running
Ex 5
I
Word problem (deadline)
Convert cycles ↔ time via clock
Ex 6
J
Exam twist: the double trap
Hidden software emulation
Ex 7
K
Exam twist: deep-pipe misprediction
"More stages" backfires
Ex 8
Each figure below carries the geometry of one derivation — look at the arrows, not just the numbers.
Worked example One pass of a 6-instruction loop on an M0 (2-stage pipeline)
A loop body has I = 6 instructions. The M0 has N = 2 stages. How many cycles for one pass?
Forecast: guess before reading — is it 6, 7, or 8 cycles?
Write the formula: Cycles = ( N − 1 ) + I .
Why this step? This is tool 1; the pipe fills once, then streams.
Substitute N = 2 , I = 6 : Cycles = ( 2 − 1 ) + 6 = 1 + 6 = 7 .
Why this step? The ( N − 1 ) = 1 is the single "warm-up" cycle the very first instruction pays; look at the assembly-line figure below — the first block needs 2 stations to exit, so exactly 1 extra cycle appears before the steady stream.
Answer: 7 cycles.
Verify: Trace by hand. Cycle 1: instr-1 in stage F. Cycle 2: instr-1 in E (finishes!), instr-2 in F. From cycle 2 onward one instruction finishes each cycle. Instr-1 finishes at cycle 2, instr-6 finishes at cycle 2+5 = 7. ✓ Matches.
Worked example 1000 passes of that same 6-instruction loop
Same M0, same body (I = 6 per pass, N = 2 ). Now run 1000 passes. Naive guess: 1000 × 7 = 7000 ?
Forecast: will it be exactly 7000 , or less?
Total instructions across all passes: I tot = 1000 × 6 = 6000 .
Why this step? The pipe never drains between iterations — instructions keep flowing — so we treat all passes as one long stream .
Apply tool 1 once: Cycles = ( N − 1 ) + I tot = 1 + 6000 = 6001 .
Why this step? You pay the fill tax once , at the very start, not per loop. That is why the answer beats the naive 7000 .
Answer: 6001 cycles , not 7000.
Verify: Difference from naive = 7000 − 6001 = 999 . That is exactly 999 saved fill-cycles — one saved per pass after the first (the first pass keeps its tax). 999 = 1000 − 1 . ✓ Sanity holds.
Worked example What does the formula do at the edges?
On an M3 (N = 3 ), evaluate: (a) I = 0 instructions, (b) I = 1 instruction, (c) the average cycles-per-instruction as I → ∞ .
Forecast: does I = 0 give 0 cycles or something weird?
(a) I = 0 : Cycles = ( 3 − 1 ) + 0 = 2 .
Why this step? Even with no useful work, if you started filling the pipe you spent 2 warm-up cycles. In practice a real program with zero instructions runs nothing, so the honest reading is: the formula describes the fill cost you'd owe — treat I = 0 as "just the tax." The clean, physical value is 2 cycles of pure overhead .
(b) I = 1 : Cycles = ( 3 − 1 ) + 1 = 3 .
Why this step? A single instruction must traverse all N = 3 stations to finish — so it takes exactly N = 3 cycles. The formula gives 3 . ✓ Consistent with "one instruction = full pipe depth."
(c) Limit: average cycles/instr = I ( N − 1 ) + I = 1 + I N − 1 . As I → ∞ , the second term → 0 , so average → 1 .
Why this step? This is why pipelining is worth it: over long streams every instruction costs essentially one cycle, i.e. IPC ideal = 1 .
Answers: (a) 2 , (b) 3 , (c) → 1 .
Verify: Plug I = 3 , N = 3 into the average: 1 + 2/3 ≈ 1.667 ; and directly ( 3 − 1 ) + 3 = 5 cycles for 3 instr = 5/3 ≈ 1.667 . ✓ The two routes agree, so the limit reasoning is sound.
Worked example M7 superscalar IPC at
p = 0 , p = 1 , and realistic p = 0.4
The M7 is dual-issue, so w = 2 . Compute IPC for three code styles: fully serial (p = 0 ), perfectly parallel pairs (p = 1 ), and typical C code (p = 0.4 ).
Forecast: what's the maximum IPC a w = 2 core can ever hit?
Formula (tool 2): IPC = 1 + p ( w − 1 ) . With w = 2 : IPC = 1 + p .
Why this step? ( w − 1 ) = 1 collapses the formula so IPC is just "1 plus the fraction of pairs that fused."
p = 0 : IPC = 1 + 0 = 1 .
Why? No pair ever issues together → the second pipe lane is idle → you're effectively single-issue. This is the lower bound .
p = 1 : IPC = 1 + 1 = 2 .
Why? Every cycle fuses two instructions → you finish 2 per cycle. This is the hard ceiling for w = 2 — you can never exceed the machine width.
p = 0.4 : IPC = 1 + 0.4 = 1.4 .
Why? Real code has dependencies (one instruction needs the previous result), so only ~40% of pairs fuse. Look at the figure — teal pairs fuse, orange singletons don't.
Answers: 1 , 2 , 1.4 .
Verify: IPC must satisfy 1 ≤ IPC ≤ w = 2 for any valid p ∈ [ 0 , 1 ] . All three (1 , 1.4 , 2 ) sit in [ 1 , 2 ] . ✓ And the p = 0.4 value 1.4 implies a speedup of 1.4 × over single-issue — matching the parent's "IPC ≈ 1.3–1.5" claim.
Worked example Latency of an interrupt on M4, with and without a busy higher-priority handler
Assume t detect = 1 cycle (sync), t stack = 12 cycles (the automatic 8-register push). Compute (G) best case with nothing blocking, and (H) worst case when a higher-priority IRQ is mid-execution and will run for 40 more cycles before it returns.
Forecast: how much does one blocking handler inflate the latency?
(G) Best case: t higher-prio busy = 0 .
L = 1 + 12 + 0 = 13 cycles.
Why this step? With nothing more urgent running, the NVIC stacks and jumps immediately — the only costs are noticing (1) and stacking (12). Look at the timeline figure: the green bar is short.
(H) Worst case: the higher-priority handler must finish first, so t higher-prio busy = 40 .
L m a x = 1 + 12 + 40 = 53 cycles.
Why this step? Your interrupt is ready but the CPU is legally busy with a more important one — determinism means this term is bounded and knowable , not zero. The red segment in the figure is that 40-cycle wait.
Answers: best 13 cycles, worst 53 cycles.
Verify: Worst − best = 53 − 13 = 40 , exactly the blocking term we injected. ✓ The formula is additive in its three bounded pieces, which is the whole point of the NVIC's deterministic design.
Worked example Will a 20 kHz control loop meet its deadline on an M4 at 168 MHz?
A motor-control ISR runs every 50 μ s (that's 20 kHz). Its body is I = 800 instructions on a 3 -stage pipeline, plus a fixed 13 -cycle interrupt entry (from Ex 5, best case). The M4 clock is 168 MHz . Does it fit?
Forecast: guess the fraction of the 50 μ s budget this eats — under half, or over?
Compute execution cycles: ( N − 1 ) + I = ( 3 − 1 ) + 800 = 802 cycles.
Why this step? Tool 1 for the ISR body.
Add interrupt entry overhead: 802 + 13 = 815 cycles total per ISR.
Why this step? The deadline must cover entry + work , not just the loop.
Convert cycles to time. One cycle at 168 MHz lasts 168 × 1 0 6 1 s .
Time = 168 × 1 0 6 815 s = 4.851 × 1 0 − 6 s ≈ 4.85 μ s .
Why this step? time = cycles ÷ frequency — frequency is cycles-per-second, so dividing cancels cycles and leaves seconds. Units: cycles/s cycles = s . ✓
Compare to the 50 μ s budget: 4.85 μ s < 50 μ s . It fits with room to spare.
Why this step? Real-time is about the deadline , and 4.85 ≪ 50 .
Answer: Yes — it uses ≈ 4.85 μ s of the 50 μ s window (≈ 9.7% ).
Verify: Utilisation = 4.85/50 = 0.097 = 9.7% . Well under 100% , so the RTOS still has ≈ 90% of every period free for other tasks. ✓
Worked example Cycle count for a PID loop written two ways on M4F
The M4F has a single-precision hardware FPU (see Fixed-point vs floating-point DSP and IEEE-754 floating point ). A PID step is 3 multiplies + 2 adds = 5 float ops. Version A uses float (hardware, ≈ 3 cycles each). Version B accidentally uses double (software emulation, ≈ 40 cycles each). Compare.
Forecast: how many times slower is the accidental double version?
Version A (float): 5 × 3 = 15 cycles.
Why this step? Each single-precision op runs in silicon in ~3 cycles.
Version B (double): 5 × 40 = 200 cycles.
Why this step? The M4F FPU is 32-bit only; every 64-bit double op silently calls a software routine — the FPU sits unused. This is the parent's "3.14 vs 3.14 f " trap.
Slowdown ratio: 200/15 = 13. 3 × .
Why this step? The exam wants you to notice a silent ∼ 13 × penalty from one missing f suffix.
Answers: A = 15 cycles, B = 200 cycles, ratio ≈ 13.3 × .
Verify: 15 × 13. 3 = 200 . ✓ Fix: write 3.14f and call sinf, not sin. Only M7 offers optional double -precision hardware.
Worked example Effective cost of a mispredicted branch: M0 (2-stage) vs M7 (6-stage)
A branch misprediction forces the CPU to throw away the partially-filled pipe and refill it. The refill penalty is ( N − 1 ) cycles (the same fill tax, paid again). A branchy ISR mispredicts 30 times. Compare the wasted cycles on M0 (N = 2 ) versus M7 (N = 6 ).
Forecast: does the "faster" M7 waste more or fewer cycles here?
M0 penalty per miss: N − 1 = 2 − 1 = 1 cycle. Total = 30 × 1 = 30 cycles.
Why this step? A shallow pipe refills almost instantly — only 1 stage to reload.
M7 penalty per miss: N − 1 = 6 − 1 = 5 cycles. Total = 30 × 5 = 150 cycles.
Why this step? A deep pipe had 5 stages of in-flight work to discard and reload — depth is a liability for branchy code.
Ratio: 150/30 = 5 × more wasted cycles on M7 per misprediction burst .
Why this step? This is exactly the parent's warning: "more stages is not always faster." Deep pipelines (see Pipelining and superscalar execution ) buy clock speed , not free IPC — and they lose on unpredictable branches.
Answers: M0 wastes 30 cycles, M7 wastes 150 cycles, ratio 5 × .
Verify: Penalty scales linearly with ( N − 1 ) : M7/M0 = ( 6 − 1 ) / ( 2 − 1 ) = 5 . ✓ Matches the 150/30 = 5 computed. Lesson: for tiny, branchy, GPIO-poking control code, a 2-stage M0+ can be more deterministic than an M7.
Do :::
Cells-covered A (Ex1), B (Ex2), C+D (Ex3), E+F (Ex4), G+H (Ex5), I (Ex6), J (Ex7), K (Ex8)
One-pass cycles for I = 6 on a 2-stage pipe ( 2 − 1 ) + 6 = 7
Why 1000 passes ≠ 1000 × one pass the fill tax ( N − 1 ) is paid only once
Max IPC of a dual-issue core w = 2 (at p = 1 )
Why double is slow on M4F its FPU is single-precision only, so double falls back to software emulation
Why deep pipelines hurt branchy code misprediction refill penalty is ( N − 1 ) cycles — bigger N , bigger waste
Mnemonic "Fill once, flush per miss"
You pay the pipe-fill tax ( N − 1 ) once at start (Ex 2) — but you pay it again on every mispredicted branch (Ex 8). Deep pipes love long straight streams and hate surprises.