AMBA AHB · Module 17
Error-Response Testing
Driving and verifying ERROR scenarios — deliberately injecting the conditions that should produce an ERROR (reserved/unmapped address, illegal access type, protection violation, unsupported size), because the happy path never produces errors. For each, verify three things: the two-cycle ERROR sequence is correct (HRESP=ERROR both cycles, HREADYOUT low then high), the slave state is unchanged (an errored write modified nothing — checked by the scoreboard), and the master samples the error and takes the fault. The hardest corners: an error in the middle of a burst (terminate cleanly, cancel the pipelined next beat) and an error while the master pipelines the next transfer. AHB-Lite uses only OKAY and ERROR.
Waits (17.7) and bursts (17.8) stress the timing and structure; this chapter stresses the failure path — the ERROR response. Error handling is a classic verification gap: the happy path never produces errors, so unless you deliberately inject them, the entire error-handling logic — the two-cycle ERROR sequence (16.6), the state-suppression, the master's fault handling — goes untested. Error-response testing drives the conditions that should produce an ERROR (a reserved/unmapped address, an illegal access type like a write to a read-only register, a protection violation, an unsupported size) and verifies the design handles them correctly. For each injected error, you verify three things: (1) the two-cycle ERROR sequence is correct (HRESP = ERROR for both cycles, HREADYOUT low then high, the master samples ERROR at HREADYOUT high — 16.6); (2) the slave state is unchanged (an errored write modified nothing — checked by the scoreboard); (3) the master handles it (samples the error, takes the bus fault). The hardest corners: an error in the middle of a burst (terminate the burst cleanly, earlier OKAY beats took effect, cancel the pipelined next beat) and an error coinciding with the master pipelining the next transfer. (AHB-Lite uses only OKAY/ERROR — RETRY/SPLIT are full AHB.) This chapter builds error-response testing.
1. What Is It?
Error-response testing is targeted verification of the ERROR path — injecting errors and verifying the handling. Its parts:
- Inject the triggers — drive the conditions that should error: reserved/unmapped address, illegal access (write RO / read WO), protection violation, unsupported size.
- Verify the two-cycle sequence —
HRESP = ERRORfor both cycles,HREADYOUTlow then high; the master samples ERROR atHREADYOUThigh. - Verify no state change — an errored write modified nothing (the scoreboard confirms the target is unchanged).
- Verify the master + corners — the master takes the fault; the hardest corners are error mid-burst and error + pipelined-next.
So error-response testing is the deliberate exercise of the failure path — the part of the design that only runs when something goes wrong, and is therefore most likely to be untested (and buggy). The insight is that error handling is invisible on the happy path: a test that only does valid accesses never triggers an error, so the entire error-handling logic (the two-cycle sequence, the state-suppression, the master's fault response) is never executed. So error-response testing must deliberately inject the error triggers (reserved addresses, illegal accesses, protection violations, bad sizes) — creating the failure conditions. And then it verifies the three aspects of correct error handling: the protocol (the two-cycle sequence is right), the safety (no state change — the invalid access was inert), and the system (the master faults). The corners — error mid-burst (the intersection with burst sequencing) and error + pipelined-next (the intersection with the pipeline) — are where error bugs cluster. So error-response testing is the deliberate injection and verification of the error path. So it's how you test what happens when things go wrong.
2. Why Does It Exist?
Error-response testing exists because the error path is never exercised by the happy path (so it's the most likely to be untested and buggy), because correct error handling has multiple distinct aspects (the two-cycle sequence, the state-suppression, the master's fault — each must be verified), and because errors intersect with the hardest features (bursts, the pipeline) — so deliberate injection and multi-aspect verification are essential.
The error path is never exercised normally is the root: a normal (valid) access never produces an error — so a happy-path test never runs the error-handling logic. As a result, the error logic (the two-cycle sequence, the suppression, the fault) is the least-tested part of the design — and least-tested means most-likely-buggy. So you must deliberately inject errors to exercise that logic at all. So error-response testing exists to force the error path. So it's deliberate injection. So the untested path demands it.
The multiple aspects to verify drives the multi-check: correct error handling isn't one thing — it's three: the protocol (the two-cycle sequence — does the slave drive HRESP/HREADYOUT correctly?), the safety (no state change — did the errored access corrupt anything?), and the system (the master's fault — does the master react correctly?). Each is a separate potential bug. So error-response testing must verify all three (a slave could get the sequence right but still corrupt state, or vice versa). So it exists to verify the multiple aspects. So it's multi-check. So the aspects demand thoroughness.
The errors intersect the hardest features is the corner focus: an error doesn't happen in isolation — it can occur mid-burst (intersecting burst sequencing — does the burst terminate cleanly?) or while the master pipelines the next transfer (intersecting the pipeline — is the next transfer cancelled?). These intersections are where error bugs cluster (the combination of error + burst, or error + pipeline, stresses both). So error-response testing must drive these corners. So it exists to cover the intersections. So it's corner-focused. So error-response testing exists because: the error path is never exercised normally (least-tested, most-likely-buggy — must deliberately inject — the why); correct handling has multiple aspects (two-cycle sequence + no-state-change + master-fault — each verified — the multi-check); and errors intersect the hardest features (mid-burst, pipelined-next — where bugs cluster — the corners). So error-response testing is the deliberate injection and multi-aspect verification of the failure path — exercising the least-tested, most-likely-buggy logic, especially at its hardest intersections. So this chapter forces and verifies the error path. So inject errors, verify all three aspects, drive the corners.
3. Mental Model
Model error-response testing as a fire-drill program for a building, not just checking the building works on a normal day. On a normal day (the happy path), the fire alarm, sprinklers, and evacuation routes are never used — so you have no idea if they work. You must deliberately trigger a drill (inject an error) to test them. And you check three things: the alarm sounds correctly (the two-cycle ERROR sequence), nothing valuable is damaged by the drill (no state change — the errored access didn't corrupt anything), and people evacuate properly (the master takes the fault). The hardest drill is one during a busy event (mid-burst) — does the event stop cleanly and everyone still get out?
A building (the design) that must handle emergencies (errors). On a normal day (the happy path), the emergency systems — the fire alarm, the sprinklers, the evacuation routes — are never used. So you have no idea whether they work: the alarm might be broken, the sprinklers might flood the wrong floor, the exits might be blocked — and you'd never know, because nothing ever triggers them. The only way to test them is to deliberately run a fire drill (inject an error) — create the emergency condition on purpose. And when you run the drill, you check three distinct things. First: does the alarm sound correctly — the right pattern, loud enough, for the right duration (the two-cycle ERROR sequence — HRESP/HREADYOUT correct)? Second: does the drill avoid damaging anything valuable — the sprinklers don't go off and ruin the server room, the drill doesn't corrupt the building's contents (the errored access doesn't change state — no corruption)? Third: do people evacuate properly — they hear the alarm and follow the routes out (the master samples the error and takes the fault)? And the hardest drill is one triggered during a busy event — a conference in progress (a burst mid-flight): does the event stop cleanly at the alarm, do the people already served keep what they got (the earlier OKAY beats took effect), does nobody get half-served (the errored beat changed nothing), and does everyone scheduled next get cancelled and evacuated (the pipelined next beat is cancelled)? You must run drills during busy events, not just on quiet days, because that's the hardest case.
This captures error-response testing: the normal day never using the emergency systems = the happy path never exercising the error path; deliberately running a fire drill = injecting the error triggers; the alarm sounding correctly = the two-cycle ERROR sequence; the drill not damaging anything = no state change (errored access inert); people evacuating properly = the master taking the fault; the hardest drill during a busy event = an error mid-burst; the event stopping cleanly, served people keeping what they got, next ones cancelled = the burst terminating cleanly with earlier OKAY beats effective and the pipelined next cancelled. Deliberately run the drill, check the alarm + no-damage + evacuation, and run it during a busy event.
Watch an error mid-burst terminate cleanly:
An error mid-burst terminates cleanly
4 cyclesThe model's lesson: deliberately run the drill, check the alarm + no-damage + evacuation, and run it during a busy event. In the waveform, the error mid-burst (beat 2, reserved) is handled across all aspects — the two-cycle sequence runs, the errored beat changes nothing (A2 unchanged), the earlier OKAY beats took effect, the burst terminates, and the pipelined next beat is cancelled.
4. Real Hardware Perspective
In the testbench, error-response testing is implemented by an error-injecting sequence (driving the error triggers), the two-cycle-ERROR assertion (17.2), the scoreboard checking no state change on errored writes, a master/fault check, and coverage on the response/error crosses — with deliberate mid-burst and pipelined-next injection.
The error-injecting sequence: the stimulus deliberately generates the error triggers — accesses to reserved addresses (from the address map's holes), writes to read-only registers, reads of write-only locations, protection-violating accesses (wrong HPROT), unsupported sizes. A constrained-random sequence (17.6) biases toward these (since random legal traffic rarely hits them). So in the testbench, the sequence injects the errors. So it's error generation. So that's the stimulus.
The three-aspect verification: each injected error is verified three ways. (1) The two-cycle sequence: the assertion (HRESP==ERROR && !HREADY) |=> (HRESP==ERROR && HREADY) (17.2) checks the sequence; if the slave does a one-cycle error or drops HRESP, it fires. (2) No state change: the scoreboard (17.4) — before the errored write, it records the target's value; after, it verifies the target is unchanged (the errored write did not update it). For a side-effecting target, it verifies no side effect. (3) Master fault: a check that the master samples ERROR (at HREADYOUT high) and takes the fault (the expected exception/recovery). So in the testbench, the three aspects are checked by assertion + scoreboard + master-check. So it's multi-aspect. So that's the verification.
The corner injection + coverage: the sequence deliberately injects errors mid-burst (an error on a middle beat — verifying termination, earlier-beats-effective, cancel-next) and with the master pipelining the next transfer (verifying cancellation). And coverage (17.5) confirms the error scenarios were hit — cp_resp ERROR, cp_dir × cp_resp (read-error and write-error), cp_burst × cp_resp (error in each burst type), and error-position (error on beat 0/middle/last). So in the testbench, error-response testing is an error-injecting sequence + three-aspect checks (assertion/scoreboard/master) + corner injection (mid-burst, pipelined-next) + coverage. The skill is injecting all the error types and corners and verifying all three aspects. So in the testbench, inject deliberately, verify three aspects, drive the corners, confirm via coverage. So that's the implementation.
5. System Architecture Perspective
At the system level, error-response testing is critical because error handling is the safety and robustness path — errors are how the system detects and contains faults, so a broken error path means faults go undetected or corrupt state; it's also the least-tested path (so the highest-risk), and the error injection capability is a reusable VIP component.
The safety/robustness path: error handling is the system's fault-detection and containment mechanism — an ERROR is how a bad access (a bug, an attack, a fault) is caught and contained (the master faults, the state is protected). So if error handling is broken — the sequence wrong (master misses the error), or state changed (the bad access corrupted something) — then faults go undetected or cause corruption. So error handling is safety-critical. So at the system level, testing it protects the system's fault-handling. So it's the safety path. So errors matter for robustness.
The highest-risk least-tested: because the error path is never exercised normally, it's the least-tested — and the least-tested path is the highest-risk (most likely to ship buggy). So error-response testing has high importance precisely because the path is otherwise neglected. So at the system level, it de-risks the most-neglected logic. So it's high-value risk reduction. So neglect makes it critical.
The reusable error injection: the error-injection capability (driving the triggers) and the error checks (the two-cycle assertion, the no-state-change scoreboard check) are reusable — part of the VIP (17.11). Every AHB verification needs error testing. So at the system level, error-response testing is safety-critical (error handling is the fault-detection/containment path — a broken error path means undetected faults or corruption), the highest-risk least-tested path (never exercised normally → de-risking the most-neglected logic), and a reusable VIP capability (error injection + error checks). So error-response testing is where the system's fault-handling is verified — the deliberate exercise of the safety path that the happy path neglects, especially at its hardest intersections (mid-burst). So inject the errors — the system's safety depends on the error path working. So test the failure path deliberately.
6. Engineering Tradeoffs
Error-response testing embodies the deliberate-injection, three-aspect, corner-driven design.
- Inject errors vs happy-path-only. Injecting errors exercises the (otherwise-untested) error path; happy-path-only leaves it unverified. Always inject errors (the path is neglected otherwise).
- Three-aspect vs sequence-only. Verifying all three (sequence + no-state-change + master-fault) catches all error bugs; checking only the sequence misses state-corruption and master-handling bugs. Verify all three.
- Mid-burst/pipelined corners vs isolated errors. Driving errors mid-burst and with pipelined-next finds the intersection bugs (where errors cluster); isolated errors miss them. Drive the corners.
- No-state-change check vs assume. Explicitly verifying the errored write changed nothing (scoreboard) catches state-corruption (a safety bug); assuming misses it. Verify no-state-change.
The throughline: error-response testing deliberately injects the conditions that should produce an ERROR — reserved/unmapped address, illegal access type, protection violation, unsupported size — because the happy path never produces errors, leaving the error path untested; then it verifies three aspects: the two-cycle ERROR sequence (16.6 — HRESP=ERROR both cycles, HREADYOUT low→high), the slave state unchanged (an errored write modified nothing — scoreboard), and the master taking the fault. The hardest corners — error mid-burst (terminate cleanly, earlier OKAY beats effective, cancel next) and error + pipelined-next (cancel) — are where error bugs cluster. It's driven by constrained-random injection (17.6) and confirmed by coverage (17.5, on the response crosses). It's safety-critical (the fault-detection/containment path), the highest-risk least-tested path, and a reusable VIP capability. (AHB-Lite = OKAY/ERROR only.)
7. Industry Example
Run error-response testing on the 16.x slaves, verifying all three aspects across the corners.
You're verifying the slaves' error handling. You inject errors and verify all three aspects, including mid-burst.
- Inject the triggers. Constrained-random (17.6) drives: accesses to reserved addresses (the register bank's holes — 16.2), writes to STATUS (read-only), reads of write-only locations, protection-violating accesses (an unprivileged access to a privileged register), and unsupported sizes.
- Aspect 1 — the sequence. The two-cycle-ERROR assertion (17.2) verifies each error is a correct two-cycle sequence (
HRESP=ERRORboth cycles,HREADYOUTlow→high). It catches a buggy one-cycle error or a droppedHRESP. - Aspect 2 — no state change. The scoreboard (17.4) records the target's value before an errored write and verifies it's unchanged after — catching a slave that (buggily) commits an errored write (e.g. a STATUS that's wrongly writable, or a protected register that changed on an unprivileged write — a security bug). For the read-to-clear register (16.2), it verifies an errored read did not clear it.
- Aspect 3 — the master fault. A check verifies the master samples the ERROR at
HREADYOUThigh and takes the fault (and cancels the pipelined next transfer). - The mid-burst corner. The sequence injects an error on a middle beat of an INCR burst — verifying the burst terminates at the error, the earlier OKAY beats took effect (their data is in the slave), the errored beat changed nothing, and the master cancels the remaining beats. (A buggy slave that continued the burst, or committed the errored beat, is caught.)
- Coverage confirmation. The
cp_respERROR,cp_dir × cp_resp(read-error and write-error),cp_burst × cp_resp(error in each burst type), and error-position coverpoints are closed — confirming the error scenarios (including mid-burst) were exercised.
The example shows error-response testing exercising the neglected failure path across all three aspects (sequence, no-state-change, master-fault) and the hardest corner (mid-burst) — catching the protocol, safety, and system error bugs that the happy path would never reveal. This is the safety path verified. This is testing what happens when things go wrong.
8. Common Mistakes
9. Interview Insight
Error-response testing is a high-signal verification interview topic — the inject-deliberately insight, the three-aspect verification, and the mid-burst-corner awareness are the signals.
The answer that lands gives the inject-deliberately insight and the three aspects: "Error-response testing deliberately injects the conditions that should produce an ERROR, because the happy path never produces errors — so the entire error-handling logic, the two-cycle sequence, the state suppression, the master's fault handling, goes untested unless you force it. The error path is the least-tested part of the design, which makes it the highest-risk. So I inject the triggers: accesses to reserved or unmapped addresses, illegal access types like writing a read-only register or reading a write-only one, protection violations, and unsupported sizes. For each injected error, I verify three independent things. First, the two-cycle ERROR sequence is correct — HRESP is ERROR for both cycles, HREADYOUT goes low then high, and the master samples ERROR when HREADYOUT goes high. Second — and this is the one people miss — the slave state is unchanged: the errored write must not have modified any register or memory. I check this with the scoreboard, because a slave can produce a perfect ERROR sequence while still committing the errored write, which is a safety bug, especially for a protection violation where a forbidden write must change nothing. Third, the master handles it — samples the error, cancels the pipelined next transfer, and takes the bus fault. The hardest corner is an error in the middle of a burst: the burst must terminate cleanly at the error, the earlier OKAY beats must have taken effect, the errored beat must change nothing, and the master must cancel the remaining beats. That's the intersection of error handling, the two-cycle sequence, and burst sequencing, where subtle bugs cluster — like the slave continuing the burst after the error. So I deliberately inject errors mid-burst, on beat zero, a middle beat, and the last beat. And I confirm via coverage that the error scenarios were hit — read-error and write-error, error in each burst type, error at each position. One note: AHB-Lite only has OKAY and ERROR; RETRY and SPLIT are full AHB, and a busy slave inserts wait states, not a RETRY." The inject-deliberately insight, the three-aspect verification, and the mid-burst-corner awareness are the senior signals.
10. Practice Challenge
Build and reason from error-response testing.
- Inject deliberately. Explain why errors must be deliberately injected, and list the triggers (reserved/illegal/protection/size).
- Three aspects. Describe the three things to verify per error (two-cycle sequence, no state change, master fault) and why all three.
- Read the waveform. From Figure 2, explain how the mid-burst error is handled (earlier beats effective, errored beat unchanged, burst terminates, next cancelled).
- Sequence-correct-but-buggy. Explain how a slave can produce a correct ERROR sequence yet corrupt state, and how the scoreboard catches it.
- The hardest corner. Explain why an error mid-burst is the hardest corner and what must be verified.
11. Key Takeaways
- Error-response testing deliberately injects errors — the happy path never errors, so the error path (the least-tested, highest-risk logic) is only exercised by deliberate injection of the triggers (reserved/illegal/protection/size).
- Verify three independent aspects — the two-cycle ERROR sequence (16.6), the slave state unchanged (no corruption — scoreboard), and the master takes the fault. Checking only the sequence misses the others.
- A correct sequence can still hide a safety bug — a slave can sequence perfectly while committing the errored write (state corruption — especially a protection violation: a forbidden write must change nothing). Verify no state change.
- The hardest corner is mid-burst — the intersection of error handling + the two-cycle sequence + burst sequencing: terminate cleanly, earlier OKAY beats effective, errored beat unchanged, cancel the pipelined next. Inject at every beat position.
- Verify the master too — it must sample the ERROR (at
HREADYOUThigh), cancel the pipelined next, and take the fault. - It's safety-critical — error handling is the fault-detection/containment path; confirm via coverage (
cp_dir × cp_resp,cp_burst × cp_resp, error-position). AHB-Lite =OKAY/ERRORonly.
12. What Comes Next
You now can verify the failure path. The next chapters verify the bridge and assemble the VIP:
- Bridge Verification (next) — verify the AHB-to-APB bridge end-to-end (combining all the targeted tests across the bridge).
- UVM AHB Agent — assemble the driver/sequencer/monitor into a reusable AHB agent (the VIP).
To revisit the error response this drives, see HRESP Generation, The Two-Cycle ERROR Response, and How the Master Reacts; for the checks it uses, see AHB Assertions (SVA) and AHB Scoreboards.