Intuition What this page is
The parent note gave you the rules : instructions
execute as-if sequentially, and exceptions must be precise (the machine looks like it stopped
cleanly on one instruction boundary). This page throws every kind of case at those rules — every
exception family, every "which PC do we return to?" branch, the zero/degenerate inputs, the
tie-breaking edge, an asynchronous interrupt, and an exam twist — and works each one fully.
If you can predict all of these, nothing on an exam can surprise you.
Before any example, we must define one idea the parent note only hinted at, because every
"which PC?" answer secretly depends on it.
Intuition What is a pipeline, in one picture?
A modern CPU does not do one instruction start-to-finish before touching the next. Instead it runs
them like an assembly line — several instructions in flight at once, each in a different stage :
fetch the bytes, decode them, execute the math, access memory, and finally write the
result back so the outside world can see it . Look at the coloured lane in the figure below: an
instruction slides left-to-right through the stages.
Definition Commit (also called
retire )
An instruction commits (equivalently, retires ) at the exact moment its result becomes part of
the architectural state — the registers/PC/memory a programmer can see. Before commit, all of
its work lives only in hidden microarchitectural buffers (the reorder buffer ) and can still be thrown away. After commit, it is permanent.
The two words mean the same thing; "retire" stresses leaving the pipeline, "commit" stresses
making state visible . We use them interchangeably.
Intuition Why commit is THE dividing line for exceptions
Instructions may compute out of order internally, but they commit strictly in program order
(the reorder buffer enforces this — see the green "retire in order" arrow in the figure). This gives
us one clean rule that powers every example:
An exception is only real once the faulting instruction reaches commit. Anything not yet
committed can be squashed (silently discarded) as if it never ran — which is exactly how the
machine stays precise .
To discard an instruction and all its effects before commit , so it leaves no trace in
architectural state. Wrong-path speculation and instructions younger than a fault are squashed.
Two model conventions we fix up front so nothing later is ambiguous:
Definition Our machine's conventions (stated so you can trust the answers)
Divide-by-zero is treated as a FAULT here (return to the same instruction). This is a choice ,
not a law — see the callout in Ex 4. Real ISAs differ.
A trap on this page means any synchronous, instruction-caused event whose "job" completes , so
we resume at the next instruction. That includes deliberate SYSCALL, breakpoints, and (on some
machines) invalid-opcode and divide-error. "Deliberate" is the easiest trap, not the only one.
Here is the full grid of case-classes this topic can throw at you. The figure right after it is the
same grid drawn as a coloured map, so you can see at a glance how the nine cases partition the space
of behaviours (by return-PC rule on one axis, cause on the other).
#
Case class
The distinguishing question
Covered by
A
Fault on a memory access
Return to same instruction
Ex 1
B
Trap (deliberate)
Return to next instruction
Ex 2
C
Abort (unrecoverable)
No return at all
Ex 3
D
Zero / degenerate input (÷0)
Fault triggered by data, not address
Ex 4
E
Tie-break — two faults same cycle
Report the program-order-oldest
Ex 5
F
Asynchronous interrupt
Not tied to one instruction; where to insert it
Ex 6
G
Speculative / squashed instruction faults
A fault that must be thrown away
Ex 7
H
Word problem (real syscall trace)
Chain several rules together
Ex 8
I
Exam twist — branch delay / limiting PC
Which PC when the faulting instr also changes PC?
Ex 9
Two ideas repeat across every cell, so pin them now:
Recall The one number that decides everything: the return PC
Which PC does the handler save into the Exception PC (EPC) ?
Fault ::: the address of the faulting instruction itself (retry it)
Trap ::: the address of the next instruction (we already did the job)
Abort ::: no return — the program is killed
Interrupt ::: the address of the next instruction not yet committed (resume where we paused)
Assume a fixed-length ISA: every instruction is 4 bytes , so "next instruction" means
"current address + 4 " unless a branch says otherwise.
LW R5, 0(R6) at address 0x1000, page not resident
The page holding the address in R6 is not in physical memory, so the hardware raises a page fault .
Forecast: guess before reading — after the OS loads the page, does execution resume at 0x1000,
0x1004, or somewhere else? And is R5 written or untouched?
Classify. This is a fault (see Virtual Memory and Page Faults ): correctable, detected
before the instruction commits.
Why this step? The family determines the return PC; everything else follows from it.
State check. Because the exception must be precise , R5 is not modified — no half-load.
Why? If R5 were partly written, re-running the load would be unsafe; precision guarantees a clean
restart point. (The LW never committed, so nothing it computed reached R5.)
Return PC. E P C = 0 x 1000 — the address of the LW itself .
Why? The OS fixes the missing page, then the same load must run again to actually fetch data.
Verify: After handling, the CPU jumps to 0x1000, re-executes LW, and this time the page is
present, so R5 gets its value. No instruction was skipped, none double-ran. E P C = 0x1000 = 4096 .
The figure below places this fault vs a trap on the same picture so the EPC arithmetic is visual.
SYSCALL at address 0x2040
The program deliberately requests an OS service (see System Calls and Privilege Levels ).
Forecast: return to 0x2040 or 0x2044?
Classify. A trap — synchronous and its "meaning" (issue the request) completes and
commits . (A breakpoint or invalid-opcode trap would classify the same way.)
Why? The program asked for it; we want to continue afterward, not repeat the request.
Return PC. E P C = 0 x 2040 + 4 = 0 x 2044 — the next instruction.
Why + 4 ? Re-running the syscall would issue the request twice (e.g. write bytes twice).
Verify: 0 x 2040 + 4 = 0 x 2044 . Contrast with Ex 1: same mechanism (jump to handler, save EPC),
opposite EPC choice — purely because the trap committed its job and the fault did not.
Worked example Abort: uncorrectable ECC error while fetching an instruction at
0x30A0
Memory returns data that fails its error-correcting-code check and cannot be repaired.
Forecast: what EPC do we compute?
Classify. An abort — unrecoverable hardware failure.
Why? No amount of "try again" fixes corrupted physical memory.
Return PC. There is none meaningful. The OS logs the fault and typically kills the process
(or panics if it was kernel state).
Why? Precise-restart semantics assume the cause can be removed. Here it cannot, so restart is
impossible by definition.
Verify: The matrix predicts "restartable? = No" for aborts — consistent. Unlike Ex 1/Ex 2, no
arithmetic on the PC is even required.
Worked example Data-triggered fault:
DIV R7, R8, R9 at 0x4000 with R9 = 0
Integer division by zero.
Forecast: is this a fault or a trap? Which PC?
State our convention (read this first!). Whether ÷0 is a fault or a trap is an ISA design
choice , not a universal truth. Many real ISAs (e.g. x86 #DE) treat divide-error as a trap
and return to the next PC. This page's abstract machine treats it as a FAULT so we can
illustrate the "retry after fixing the cause" behaviour on a data-driven condition.
Why call it out? If you skip this, the answer looks contradictory next to a real x86 manual.
Classify (under our convention). A fault — detected before R7 is written, restartable
in principle (the OS could deliver a signal and let a handler fix the operand).
Why? The division never produced a valid result, so nothing committed — R7 is untouched.
Degenerate-input note. Unlike Ex 1, the trigger is the operand value (R9 = 0), not an
address. The exception fires purely from data .
Why this matters? Re-running unchanged would fault again — so the OS must change something (fix
R9, or advance the PC in a signal handler) before resuming.
Return PC (our convention). E P C = 0 x 4000 — the DIV itself.
Why? Fault rule: retry the faulting instruction after the cause is addressed. (On an ISA that
makes it a trap, EPC would instead be 0 x 4000 + 4 = 0 x 4004 .)
Verify: R 9 = 0 makes R 8/ R 9 undefined, so R7 stays untouched — precise. Fault EPC
= 0 x 4000 = 16384 ; the trap-convention alternative would be 0 x 4004 = 16388 .
DIV at 0x5010 (÷0) and older LW at 0x5008 (page fault), detected same cycle
Both exceptions are ready in the same clock cycle. In program order the LW (0x5008) is older
than the DIV (0x5010).
Forecast: which exception does the CPU report first?
Order rule. Report the exception of the program-order-oldest faulting instruction ⇒ the
LW at 0x5008.
Why? Precise semantics says everything before the reported fault must have committed . If we
reported the DIV first, we'd be claiming the LW committed — but it didn't (it faulted).
Impossible in the sequential world.
What happens to the DIV? It is squashed (discarded before commit) and not reported yet.
After the OS handles the page fault and restarts at 0x5008, execution flows forward and may
reach the DIV again, which will fault a second time — and then be reported.
Why? Only one clean commit boundary exists at a time; the oldest un-committed fault owns it.
Verify: 0 x 5008 < 0 x 5010 , so the LW is older ⇒ reported ⇒ E P C = 0 x 5008 = 20488 . The DIV's
fault is deferred, matching the Out-of-Order Execution and the Reorder Buffer retire-in-order rule.
Worked example Interrupt: timer fires while the CPU is between
0x6100 and 0x6104
A hardware timer (see Interrupts and I/O ) raises an interrupt — nothing to do with the current
instruction's data.
Forecast: is the return PC tied to a faulting instruction? Where do we resume? And what if the
timer fires at the same time as a page fault?
Classify. An interrupt — asynchronous . It is not caused by any instruction's semantics.
Why this matters? Re-running the program would not reproduce it at the same spot (unlike an
exception, which is a deterministic function of the instruction stream).
Masking check. Interrupts can be masked — temporarily blocked when the CPU is in a critical
region or already servicing a higher-priority handler. If the timer is masked, it simply waits
(stays pending ) until unmasked; the current instruction stream is undisturbed.
Why include this? Faults and traps cannot be masked (they are part of an instruction's
meaning); interrupts can . That is a real, testable difference.
Priority. If several interrupts are pending, the CPU takes the highest-priority one first;
lower ones stay pending. A timer might outrank a keyboard, for example.
Insertion point (if unmasked). Hardware picks a clean commit boundary : it lets the
instruction at 0x6100 commit, squashes younger not-yet-committed work, and records the next
uncommitted PC.
Return PC. E P C = 0 x 6104 — resume at the next instruction that had not yet committed.
Why + 4 ? We are pausing, not retrying; the instruction at 0x6100 already committed.
Coincidence rule (interrupt + exception same cycle). A synchronous exception wins over an
asynchronous interrupt on the same boundary: the exception belongs to the instruction stream and
must be handled to keep state precise; the interrupt is still pending and taken immediately after.
Why? Delivering the interrupt "over" an un-handled fault would leave imprecise state.
Verify: 0 x 6100 + 4 = 0 x 6104 . Same EPC arithmetic as a trap (Ex 2), but the cause is external,
not the instruction — the "synchronous vs asynchronous" distinction from the parent note.
Worked example Squashed fault: a branch is mispredicted; a speculatively-fetched
LW on the wrong path faults
The pipeline guessed a branch outcome and ran ahead. On the wrong (mispredicted) path sits a LW
that would page-fault. Later the branch resolves — the guess was wrong.
Forecast: does the OS ever see this page fault?
Recognise the trap-door. A fault is only real once the faulting instruction reaches commit
(this is exactly the rule we defined at the top). Speculative instructions have not committed .
Why? Architectural state only changes at commit; before that, everything is provisional
microarchitectural state.
Squash. When the branch resolves wrong, the LW and all wrong-path work are squashed
(discarded — see Pipelining and Hazards ). Its page fault is discarded with it .
Why? In the sequential model that LW never executes — so its fault must never be visible.
Result. No exception is reported. The OS is never told.
Why? Reporting a fault from an instruction that "never ran" would violate precise semantics.
Verify: Compare to Ex 1: identical LW page fault, but here it is on a squashed path, so
"exception reported" flips from yes to no . The deciding factor is always did it commit?
write() call that also crosses a missing page
A program runs, in order:
Addr
Instr
Note
0x8000
LW R1, 0(R2)
loads a byte-count, page present
0x8004
LW R3, 0(R4)
page not resident
0x8008
SYSCALL
requests write()
Forecast: what is the first exception, its EPC, and what is the final EPC after everything
resolves and the syscall completes?
First instruction (0x8000). Commits normally; R1 written; PC advances.
Why start here? Precision needs older instructions fully committed before any later fault is reported.
Second instruction (0x8004). Page fault → fault → E P C = 0 x 8004 (retry).
Why not skip to the syscall? The LW is older; its un-committed fault owns the boundary (Ex 5 rule).
OS handles it, restarts at 0x8004. Page now present; R3 loads and commits; PC advances to
0x8008.
Why re-run the whole LW? Fault semantics = retry the faulting instruction (Ex 1).
Third instruction (0x8008). SYSCALL → trap → after servicing, resume at
E P C = 0 x 8008 + 4 = 0 x 800 C .
Why + 4 ? The syscall committed its job; continue past it (Ex 2).
Verify: First reported exception EPC = 0 x 8004 = 32772 (fault). Final resume EPC after the trap
= 0 x 8008 + 4 = 0 x 800 C = 32780 . Two different EPC rules chained correctly in one trace.
Worked example Limiting case: a taken branch
BEQ R1,R2,offset at 0x9000 also triggers a fault
Suppose the branch is taken (so it wants to set PC ← 0x9000 + 4 + 4·offset) but the same
instruction raises a fault before it commits, with offset = 5.
Forecast: does EPC use the branch target or the branch's own address?
Compute what the branch would do. Taken target = 0 x 9000 + 4 + 4 ⋅ 5 = 0 x 9000 + 24 = 0 x 9018 .
Why compute it? To show that this target is only reached if the branch commits .
Apply fault rule. A fault means the instruction did not commit ⇒ its PC-update never happened.
So E P C = 0 x 9000 — the branch's own address, not the target.
Why? Fault = retry the faulting instruction from scratch. The branch has not yet decided anything
architecturally.
After the OS fixes the cause and returns to 0x9000, the branch re-executes, now commits, and
then sets the PC to 0x9018.
Why? The branch's semantics (including its PC-write) only take effect on a clean, committed run.
Verify: Would-be target 0 x 9000 + 4 + 4 ⋅ 5 = 0 x 9018 = 36888 , but E P C = 0 x 9000 = 36864
because a faulting branch never committed its PC-write. The twist: the most tempting answer (the
target) is exactly the wrong one.
Recall Reconstruct the whole matrix from one question
"Did the instruction commit , and did it want to finish?"
Fault (not committed, must retry) → EPC ::: address of the faulting instruction
Trap (committed its job) → EPC ::: address of the next instruction
Abort (uncorrectable) → EPC ::: none; process killed
Interrupt (external, paused cleanly, maskable) → EPC ::: next uncommitted instruction
Squashed speculative fault → reported? ::: never — it never committed
Two faults same cycle → report which? ::: the program-order-oldest one
Interrupt + exception same cycle → who wins? ::: the synchronous exception (interrupt stays pending)
Mnemonic "Faults stay, traps leave, aborts die."
Fault returns to the same address (stay and retry). Trap returns to the next (job done,
leave). Abort never returns (die). Interrupts behave like traps for the paused instruction — but
unlike faults/traps, they can be masked .
Back to the parent topic · this whole page is the
practical face of the hardware–software contract .