Skip to content

DFT · Chapter 3 · Scan Architecture

Working Example: Making a Counter Scannable

This capstone takes the project's 4-bit counter and makes it fully scannable end to end, proving out everything the chapter built. Its four flip-flops become mux-D scan cells, they are stitched into a scan chain, and the shift-in, capture, shift-out cycle runs with correct shift and capture modes to detect a fault that was untestable without scan. Before scan, the counter's state is reachable only by counting up from reset over many cycles and its internal carry is not observable. After scan, you load any count directly through the chain, apply one capture so the counter increments and the carry propagates, then shift the result out and compare it to the golden response. A carry stuck-at makes the captured value wrong, so the scan-out mismatches golden and the fault is detected. The fault list did not change; access did. That is exactly what scan buys.

Intermediate15 min readDFTScan InsertionCounterScan ChainCoverage

Chapter 3 · Section 3.6 · Scan Architecture — chapter capstone

Project thread — the counter (Ch1/2) becomes scannable: flops → scan cells (3.2), stitched into a chain (3.3), run through the cycle (3.3/3.4). This detects the fault 2.6 couldn't, and hands off to scan insertion (Ch4) and ATPG (Ch5).

1. Why Should I Learn This?

This lesson makes the whole chapter concrete — and shows the exact moment an untestable fault (2.6) becomes detected.

  • Convert the counter's 4 flops → mux-D scan cells (3.2), stitch a chain (3.3).
  • Load any count directly (controllability), capture one increment, shift out (observability).
  • A carry stuck-at now makes scan-out ≠ golden → detected — the fault 2.6 couldn't reach.
  • Same fault list, new access — this is scan's payoff, and the bridge to insertion (Ch4) and ATPG (Ch5).

2. Real Silicon Story — the carry fault that finally showed up

Back in 2.6, the team could model a fault on the counter's carry logic but couldn't detect it: reaching the exact pre-rollover state (1110) meant counting there over many cycles, and the carry's effect was buried in downstream logic — uncontrollable and unobservable.

After making the counter scannable, the same fault became trivial to catch. The test loaded 1110 directly into the scan chain, captured one clock (a good counter rolls to 1111), and shifted the result out. A die with carry stuck-at-0 failed to propagate the increment, so it captured the wrong value and its scan-out mismatched the golden 1111detected, cleanly, on the tester.

Nothing about the fault changed; the team simply gave the flop a save/load button (3.1). Lesson: scan turns the counter's sequential, unreachable faults into combinational, directly-testable ones — the capstone proof of the whole chapter.

3. Factory Perspective — the scannable counter through each lens

  • What the test engineer sees: a counter they can load, capture, and read — patterns become scan-in 1110 → capture → scan-out compare 1111, with a chain-integrity gate first (3.3).
  • What the yield engineer sees: counter defects (carry/state stuck-at) now fail the tester and are binnable/diagnosable, instead of escaping as in 2.6.
  • What the RTL/DV engineer sees: their ordinary counter becomes a scan-inserted counter (Ch4 does it automatically), with scan ports and a mux delay per flop — motivating scan-friendly RTL.
  • What management cares about: the coverage jump (low → high) on real logic — the tangible DPPM benefit (1.5) that justifies scan's area/timing cost, delivered by the flow this example previews.

4. Concept — the counter, before and after scan

Before scan (2.6's wall):

  • Controllability: to set count = 1110, you must count up from reset through many states — no direct access.
  • Observability: the carry rippling through the increment isn't a primary output — its faults are buried.
  • Result: the counter's state faults are largely untestable (sequential depth).

After scan (this lesson):

  1. Convert each of the 4 flops to a mux-D scan cell (3.2) — functional behavior unchanged at SE=0.
  2. Stitch them into a scan chain: scan_in → bit0 → bit1 → bit2 → bit3 → scan_out (3.3).
  3. Run the cycle (3.3/3.4):
    • Shift in (SE=1): load 1110 directly (4 shift clocks) → controllability of the exact state.
    • Capture (SE=0): one functional clock → the counter increments, the carry propagates, state becomes 1111 → combinational logic exercised.
    • Shift out (SE=1): read 1111observability; compare to golden 1111.

Detecting the carry fault:

  • Good die: loads 1110, captures 1111, scan-out = 1111match → pass.
  • Faulty die (carry SA0): the increment can't propagate past the stuck carry → captures the wrong value → scan-out 1111detected.

The punchline (2.6 realized): the fault list is identical; scan changed access, turning untestable → detected, and coverage low → high.

The counter's four bits become scan cells stitched from scan-in through count 0 to 3 to scan-out, allowing direct load and read of the countQ→SIQ→SIQ→SIscan_inload stimulus (SE=1)count[0] scan cellSI←scan_incount[1] scan cellSI←count[0]count[2] scan cellSI←count[1]count[3] scan cellSI←count[2]scan_outread response (SE=1)12
Figure 1 — the counter's four flops stitched into a scan chain (representative). Each counter bit (count[0..3]) is now a MUX-D scan cell (3.2). In functional mode (SE=0) they count as before; in shift mode (SE=1) they form a chain: SCAN-IN -> count[0] -> count[1] -> count[2] -> count[3] -> SCAN-OUT. This lets you LOAD any count directly (controllability) and READ the captured count out (observability) -- exactly the access the embedded counter lacked in 2.6.

5. Mental Model — a car odometer with a set/read dial

The counter is like a car odometer you want to test near rollover (e.g. 9999 → 10000).

  • Without scan: to test rollover you'd have to drive the car until the odometer naturally reaches 9999 — absurdly slow (sequential depth), and you can't see the internal carry between digits.
  • With scan: you install a set/read dialspin the odometer directly to 9999 (load state), drive one click (capture), and read the digits (10000 if the carry works).
  • A stuck carry shows instantly: click once from 9999 and it fails to roll to 10000 — the read reveals the wrong value.
  • You never drive thousands of miles; you set, click, read — that's shift-in, capture, shift-out.

Same odometer, same possible faults — the set/read dial (scan) makes the rollover testable in three steps instead of a road trip.

6. Working Example — the scannable counter in tri-HDL

The scan-inserted counter (behavioral, to teach structure; the tool does this in Chapter 4):

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SystemVerilog — 4-bit counter with scan (STRUCTURE; real flow: scan insertion swaps to scan library cells)
module counter4_scan (
  input  logic clk, rst_n,
  input  logic scan_in, scan_en,     // scan chain head + scan-enable
  output logic scan_out,             // scan chain tail
  output logic [3:0] count
);
  logic [3:0] nxt = count + 4'd1;    // functional next state (increment; carry ripples through)
  // Each bit is a mux-D scan cell: SE=1 -> shift (SI = previous bit); SE=0 -> functional (increment)
  always_ff @(posedge clk or negedge rst_n)
    if (!rst_n) count <= 4'd0;
    else if (scan_en) count <= {count[2:0], scan_in};  // SHIFT: scan_in -> b0 -> b1 -> b2 -> b3
    else              count <= nxt;                     // CAPTURE: normal increment
  assign scan_out = count[3];        // chain tail
endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Verilog-2001 — same scan-inserted counter
module counter4_scan (clk, rst_n, scan_in, scan_en, scan_out, count);
  input clk, rst_n, scan_in, scan_en; output scan_out; output reg [3:0] count;
  always @(posedge clk or negedge rst_n)
    if (!rst_n)        count <= 4'd0;
    else if (scan_en)  count <= {count[2:0], scan_in};  // shift
    else               count <= count + 4'd1;            // capture (increment)
  assign scan_out = count[3];
endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- VHDL — same scan-inserted counter
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all;
entity counter4_scan is
  port (clk, rst_n, scan_in, scan_en : in std_logic;
        scan_out : out std_logic; count : out std_logic_vector(3 downto 0));
end entity;
architecture rtl of counter4_scan is signal c : unsigned(3 downto 0); begin
  process (clk, rst_n) begin
    if rst_n = '0' then c <= (others => '0');
    elsif rising_edge(clk) then
      if scan_en = '1' then c <= c(2 downto 0) & scan_in;  -- shift
      else                  c <= c + 1;                     -- capture (increment)
      end if;
    end if;
  end process;
  count <= std_logic_vector(c); scan_out <= c(3);
end architecture;

The end-to-end scan test, good vs faulty:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
# Scan test on the counter — REPRESENTATIVE, SIMPLIFIED, tool-neutral (chain: scan_in->b0->b1->b2->b3->scan_out):
  SHIFT IN (SE=1, 4 clocks): load count = 1110            (controllability — reach pre-rollover state DIRECTLY)
  CAPTURE  (SE=0, 1 clock) : increment -> carry propagates -> count = 1111   (combinational logic exercised)
  SHIFT OUT(SE=1, 4 clocks): read 1111  ;  COMPARE golden = 1111
    GOOD  die  : scan_out stream = 1111 -> MATCH -> pass
    FAULTY die : carry STUCK-AT-0 -> increment can't propagate -> captures e.g. 1110 (or wrong) -> scan_out != 1111 -> DETECTED
# Same fault (2.6) -- now DETECTED, because scan gave controllability (load 1110) + observability (read 1111).

The waveform shows the full cycle — good die passes, faulty die is caught:

Counter scan test: load 1110 → capture (good=1111, faulty≠1111) → shift out & compare

10 cycles
Loading 1110, one capture makes a good counter roll to 1111 while a carry-stuck-at-0 counter captures a wrong value, detected at shift-out compareloaded 1110loaded 1110capture: good=1111, faulty=1110capture: good=1111, fa…shift out → compare golden 1111shift out → compare go…clkscan_enscan_incount_goodloadloadload1110cap1111outoutoutoutcount_faultyloadloadload1110cap1110outoutoutoutt0t1t2t3t4t5t6t7t8t9
Figure 2 — the counter's scan test cycle, good vs faulty (representative). SHIFT IN (SE=1): 4 shift clocks load count=1110 serially. CAPTURE (SE=0): one functional clock -- a GOOD counter increments 1110->1111 (carry propagates); a FAULTY counter (carry stuck-at-0) fails to roll over and captures a wrong value. SHIFT OUT (SE=1): the captured value is read out; the tester compares to golden 1111. Good -> match (pass); faulty -> mismatch (DETECTED). This is 2.6's untestable fault, now caught -- the whole chapter working end to end.

7. Industry Flow — this hand example becomes the tool flow

What we did by hand is exactly what scan insertion (Ch4) automates at scale, then ATPG and coverage follow:

The hand example of scan cells, chain, and test cycle becomes automated scan insertion, then ATPG, then coverage closureFrom the hand example to the automated structural-test flowFrom the hand example to the automated structural-test flow1This example (by hand)flops→scan cells, stitch chain, load/capture/read2Scan insertion (Ch4)automate swap + stitch + scan DRC at scale3ATPG (Ch5)generate patterns for the whole fault list4Coverage closure (Ch6)sign off the coverage → DPPM (1.5)
Figure 3 — from this hand example to the automated flow (representative). We manually: converted the counter's flops to scan cells, stitched a chain, and ran load/capture/read to detect a fault. At scale, SCAN INSERTION (Ch4) does the flop swap + stitching + scan DRC automatically for thousands of flops; ATPG (Ch5) generates the load/capture/read PATTERNS for the whole fault list; COVERAGE CLOSURE (Ch6) signs off the number. This capstone is the concrete seed of that entire downstream flow.

8. Debugging Session — the loaded count captures nonsense

1

After loading a known count into the scan chain, the captured value makes no sense, and the team suspects a logic bug in the counter; in fact scan-enable was left high (still in shift mode) during the capture clock, so the chain shifted instead of incrementing -- or chain integrity was never verified -- both are 3.3/3.4 disciplines, not counter bugs

APPLY THE SCAN DISCIPLINES: SE=0 FOR CAPTURE, AND VERIFY CHAIN INTEGRITY FIRST
Symptom

You shift in 1110, pulse the clock to capture, shift out — and the result is nonsense (not 1111, not a sensible faulty value). The team suspects the counter's increment logic is buggy.

Root Cause

The capture didn't actually happen in functional mode — scan-enable was still high, so the 'capture' clock shifted the chain instead of incrementing the counter (or the chain integrity was never verified in the first place). Two classic, non-counter causes: (1) SE left at 1 during capture (3.4): if scan-enable is still asserted when you pulse the clock, the flops are in shift mode, so instead of the counter incrementing (1110 → 1111), the chain shifts one more scan bit — producing a value that reflects the shift path, not the increment logic. The fix is to deassert SE to 0 for exactly the capture clock, then reassert it for shift-out — the shift-vs-capture discipline of 3.4. (2) Unverified chain integrity (3.3): if you never ran a flush test, the chain might not be loading 1110 correctly at all, so both the loaded state and the captured value are garbage — and you'd be 'debugging' a counter that was never given the state you think you loaded. In neither case is the counter's increment logic at fault; the issue is misapplying the scan cycle, exactly the disciplines this chapter established.

Fix

Apply the scan disciplines in order: verify chain integrity, then run the cycle with SE=1 for shift and SE=0 for exactly the capture clock. First, flush-test the chain (3.3): shift 0011 through and confirm it emerges intact, proving you can actually load 1110. Then run the cycle precisely: SE=1 for the 4 shift-in clocks (load 1110), SE=0 for the single capture clock (the counter increments to 1111), SE=1 again for the 4 shift-out clocks (read the value), and compare to golden 1111. Done correctly, a good counter yields 1111 and a carry-stuck-at-0 counter yields a wrong value that mismatches golden → detected — the intended result. The principle to lock in: making a design scannable is not just adding scan cells — it's operating the scan cycle correctly: prove chain integrity first (3.3), hold scan-enable high to shift and low for exactly the capture clock (3.4), and only then does the counter's increment (the combinational logic under test) get exercised so its faults become detectable; a nonsensical capture is almost always a scan-cycle/scan-enable mistake, not a bug in the counter. (Automated scan insertion + DRC that catch such issues at scale is Chapter 4; ATPG patterns are Chapter 5.)

9. Common Mistakes

  • Leaving SE high during capture. The counter shifts instead of incrementing — deassert SE=0 for the capture clock (3.4).
  • Skipping chain integrity. If the chain doesn't load 1110, everything after is garbage — flush-test first (3.3).
  • Thinking scan changes the counter's function. At SE=0 it counts exactly as before — scan is functionally transparent (3.2).
  • Hand-writing scan for a big design. Fine to learn on the counter; at scale, scan insertion does it (Ch4).
  • Forgetting the same fault was untestable in 2.6. The win is access, not a new fault — coverage low → high.

10. Industry Best Practices

  • Run chain integrity before capture patterns — always (3.3).
  • Drive SE precisely — high for shift, low for exactly the capture clock(s) (3.4).
  • Keep the counter scan-friendly — synchronous, clean reset (so insertion is clean, Ch4).
  • Track coverage before/after scan — the low → high delta is scan's justification.
  • Treat this as the seed of the flow — insertion (Ch4), ATPG (Ch5), coverage (Ch6) scale it up.

11. Senior Engineer Thinking

  • Beginner: "I loaded the count but the capture is nonsense — the counter logic must be broken."
  • Senior: "Did SE go to 0 for the capture clock, and did chain integrity pass? If SE stayed high, the 'capture' just shifted — nothing to do with the counter. I flush-test, then run SE=1 shift / SE=0 capture / SE=1 shift, and the good counter gives 1111, the faulty one mismatches — detected. Scan is access; operate the cycle correctly."

The senior debugs the scan cycle (SE, chain integrity), not the counter — the disciplines of 3.3/3.4 applied.

12. Silicon Impact

This capstone is the moment the abstract becomes real: the counter that was untestable in 2.6 — its state uncontrollable, its carry unobservable — becomes, through scan cells (3.2), a stitched chain (3.3), and correct shift/capture operation (3.4), a design whose faults are detected on the tester. The demonstration matters because it proves the chapter's central claim concretely: the fault list never changed; scan changed access, collapsing a sequential problem into a combinational one (3.1) — load 1110 directly, capture one increment, read 1111 — so a carry stuck-at-0 that would have escaped now fails the compare and is caught. That is the coverage low → high jump that justifies scan's area/timing cost and underwrites the part's DPPM commitment (1.5). Just as important is the operational discipline the debugging session drives home: making a design scannable is not just adding cells — you must prove chain integrity first and drive scan-enable correctly (high to shift, low for exactly the capture), or the capture is meaningless. Finally, this hand example is the seed of the entire downstream flow: scan insertion (Ch4) automates the flop-swap-and-stitch for thousands of flops with scan DRC, ATPG (Ch5) generates the load/capture/read patterns for the whole fault list, and coverage closure (Ch6) signs off the number. For the RTL/DV engineer, the lasting lesson is that a scan-friendly, synchronous counter flows cleanly through all of this — so the fault models of Chapter 2 finally protect the customer, exactly as scan promised.

13. Engineering Checklist

  • Converted the counter's flops to mux-D scan cells and stitched a chain (scan_in→count[0..3]→scan_out).
  • Verified chain integrity (flush test) before capture patterns.
  • Ran the cycle with SE=1 shift / SE=0 capture / SE=1 shift; captured the increment.
  • Detected the carry stuck-at via scan-out ≠ golden; confirmed coverage low → high vs 2.6.
  • Noted the flow scales via scan insertion (Ch4), ATPG (Ch5), coverage (Ch6).

14. Try Yourself

  1. Draw the counter's scan chain (scan_in → count[0] → count[1] → count[2] → count[3] → scan_out).
  2. Shift in 1110 (SE=1, 4 clocks); confirm the loaded state directly (controllability).
  3. Capture (SE=0, one clock): a good counter → 1111; write the carry-stuck-at-0 result.
  4. Shift out and compare to golden 1111; show the faulty die is detected.
  5. Contrast with 2.6: same fault, but untestable without scan vs detected with scan — state the coverage change.

The cycle and RTL are tool-neutral — a free simulator can run the scan counter. Real insertion/ATPG/coverage come from Chapters 4–6. No paid tool required.

15. Interview Perspective

  • Weak: "You add scan to the counter so you can test it."
  • Good: "Turn the counter's flops into scan cells, chain them, load a value, capture, and read it out to detect faults."
  • Senior: "I convert the counter's four flops to mux-D scan cells and stitch a chain (scan_in→count[0..3]→scan_out). Then I run the cycle: shift in 1110 (SE=1) to load the pre-rollover state directly — the controllability 2.6 lacked — capture one clock (SE=0) so the counter increments and the carry propagates to 1111 — the combinational logic exercised — and shift out (SE=1) to read it and compare to golden 1111 — the observability 2.6 lacked. A carry stuck-at-0 can't propagate the increment, so the captured value is wrong and scan-out mismatches → detected. Same fault list, new access — coverage jumps low → high. And I'd flush-test chain integrity first and drive SE precisely, or the capture is meaningless. At scale, scan insertion does this automatically."

16. Interview / Review Questions

17. Key Takeaways

  • Making the counter scannable = convert its 4 flops to mux-D scan cells (3.2) and stitch a chain (scan_in→count[0..3]→scan_out, 3.3).
  • The scan cycle turns the counter's sequential state into a combinational test: shift in 1110 (controllability) → capture one increment to 1111 (logic exercised) → shift out and compare to golden (observability).
  • A carry stuck-at-0untestable in 2.6 — now makes the captured value wrong, so scan-out ≠ golden → detected: the same fault list, now reachable, with coverage low → high.
  • Operate the cycle correctlyverify chain integrity first (3.3) and drive scan-enable high to shift, low for exactly the capture (3.4) — or the capture is meaningless (a scan-cycle bug, not a counter bug).
  • This hand example is the seed of the automated flow: scan insertion (Ch4) scales the swap-and-stitch, ATPG (Ch5) generates the patterns, coverage closure (Ch6) signs it off. Next: Chapter 4 — Scan Insertion & DRC (automating and checking what we did by hand).

18. Quick Revision

Making the counter scannable (Ch3 capstone). Convert the 4 counter flops → mux-D scan cells (3.2), stitch a chain scan_in→count[0..3]→scan_out (3.3). Run the cycle: shift in 1110 (SE=1 → controllability) → capture 1 clock (SE=0 → counter increments, carry propagates → 1111) → shift out & compare golden 1111 (observability). Carry stuck-at-0 (untestable in 2.6) → increment can't propagate → captured value wrong → scan-out ≠ golden → DETECTED. Same fault list, new ACCESS → coverage low → high. Operate correctly: chain integrity first (3.3), SE=1 shift / SE=0 capture (3.4) — nonsense capture = scan-cycle bug, not a counter bug. Seeds Ch4 (insertion), Ch5 (ATPG), Ch6 (coverage). Next: Chapter 4 — Scan Insertion & DRC.