Skip to content

AMBA CHI · Module 18 · CHI Debugging

Credit Issues

A credit issue freezes one channel by breaking its flow control. Credit flow control depends on conservation — every credit consumed on a send must be returned when the receiver frees the slot. A credit leak breaks that: a slot is freed but no credit returned, so the sender's count drifts down to a permanent stall — even though the receiver has room. The symptom is a sender stalling while the receiver is not full. The distinguishing signature is a count drifting down while the receiver has free slots — separating a leak from a backpressure stall. The diagnosis is a conservation check: granted must equal available plus in-flight; a short sum means a leak. Representative model, not the specification.

Advanced15 min readAMBA CHIDebuggingCredit LeakConservationFlow Control

Module 18 · Chapter 18.7 · CHI Debugging

Project thread — 18.6 debugged deadlock. 18.7 debugs credit issues; 18.8 debugs ordering violations.

1. Learning Outcomes

By the end of this chapter you should be able to:

  • Define a credit leak — credits consumed but never returned, so the count drifts down.
  • Recognize the symptom — a sender stalling while the receiver has room.
  • Distinguish a credit leak from legitimate backpressure (buffer really full).
  • Read the signature — the credit count drifting down monotonically.
  • Diagnose by credit conservation — granted = available + in-flight.
  • Implement a representative credit-leak detector in SystemVerilog, Verilog-2001, and VHDL.

2. Why Should I Learn This?

Credit-based flow control (Chapter 14.1) is what keeps a sender from overflowing a receiver — but it depends on a conservation law: every credit consumed on a send must eventually be returned when the receiver frees the slot. If a credit is lost — a slot freed without returning a credit, or a return flit dropped — the sender's usable credit count drifts down and never recovers. Eventually it hits zero and the sender stalls forever, even though the receiver's buffer has plenty of room. Throughput on that channel decays to nothing.

The trap is that this looks like backpressure — a stalled sender — but it is not: under backpressure the buffer is genuinely full and the stall resolves; under a credit leak the buffer is empty and the stall is permanent. The distinguishing signature is the credit count drifting down over time while the receiver has free slots. The diagnosis is a conservation check: the credits granted must always equal the credits available (at the sender) plus the credits in flight (slots occupied at the receiver) — and when that sum drops below the grant, a credit has leaked. This chapter is how to spot a leak versus a stall and find the accounting bug.

3. Key Terms

4. Previous Chapter Connection

This chapter debugs the credit mechanism of Chapter 14.1. The root cause is a violation of its accounting discipline — not returning a credit when a slot frees, double-consuming, or a lost return flit — so the conservation the mechanism relies on is broken. This chapter finds the leak from its drift signature.

It is the debug counterpart of Chapter 14.1's invariant, and closely related to Chapter 14.4's backpressure. There, a stall was benign — the buffer was full and the stall would resolve when the receiver drained. Here, the stall is pathological — the buffer is not full, and the stall is permanent because a credit was lost. The debug turns on distinguishing these two: same symptom (a stalled sender), opposite cause (full buffer vs leaked credit). The conservation check is what tells them apart — under backpressure conservation holds (the credits are in-flight), under a leak it is broken (the sum is short). This chapter is the flow-control-accounting debug.

5. Core Concept — check credit conservation

A credit leak is credits consumed but never returned, drifting the count down until the sender stalls with the receiver not full; the diagnosis is credit conservationgranted = available + in-flight.

  • Credits must be conserved. Every credit consumed on a send must be returned when the receiver frees the slot — so the total is constant: granted = available + in-flight.
  • A leak breaks conservation. A slot freed without returning a credit (or a lost return) loses a credit — available + in-flight drops below granted, permanently.
  • The count drifts down. With credits leaking, the sender's available count trends downward over time until it reaches zero and the sender stalls forever.
  • Not backpressure. Under backpressure the buffer is full (in-flight = granted, available = 0) and the stall resolves; under a leak the buffer has room yet the sender is stalled — conservation is violated.

The synthesis:

A credit leak is credits consumed but never returned — a slot freed without a credit return, or a lost return flit — so the sender's available count drifts down until it stalls permanently while the receiver has room. It is not backpressure (full buffer, resolving stall). The diagnosis is conservation: granted = available + in-flight must always hold; when available + in-flight < granted, a credit has leaked.

6. Engineering Mental Model — a coat-check with vanishing tickets

Think of a coat-check with a fixed number of hooks (buffer slots) and matching tickets (credits).

  • Each coat checked in takes a ticket (consumes a credit); each coat retrieved frees a hook and the ticket comes back into circulation (a credit return). The total tickets — in-hand plus on-coats — is constant.
  • Credit leak: occasionally a coat is retrieved (a hook frees) but the ticket is thrown away instead of returned to circulation. The number of tickets in circulation slowly shrinks.
  • Over time, fewer and fewer tickets exist, until there are none left to hand out — so no new coat can be checked in, even though hooks are empty. The line is stuck with an empty cloakroom.
  • To diagnose, you count: tickets-in-hand plus coats-on-hooks should equal the original ticket count. When it comes up short, tickets have leaked — and you look for the retrieval that failed to return its ticket.

The tickets are credits; the hooks are buffer slots; the shrinking count is the drift; the count-vs-original is the conservation check. A permanently stuck cloakroom with empty hooks is a leak, not a genuinely full room.

7. Engineering Diagram — the credit leak

A credit leak. The sender consumes a credit on each send; the receiver processes a flit and frees a slot, but on one such free it fails to return the credit. That credit is lost, so available plus in-flight now falls short of granted. Over repeated leaks the sender's credit count drifts to zero and it stalls, though the receiver's buffer has free slots.SenderReceiverflit (consume acredit)process flit, free aslotcredit return(MISSING — leak!)credit count driftsdown → stall
Figure 1 — a credit leak. The sender consumes a credit on each send; the receiver processes a flit and frees a slot, but on one such free it fails to return the credit. That credit is lost — available plus in-flight now falls short of granted. Over repeated leaks the sender's credit count drifts to zero and it stalls, though the receiver's buffer has free slots.

The receiver freed a slot but did not return the credit — that credit is lost. Repeated, the sender's count drifts to zero and it stalls, though the buffer has room. The bug is the missing credit return on a slot free — found by the conservation shortfall. The debugger sees the count drift with an empty buffer.

8. Waveform Signature

Credit leak: count drifts down while the buffer has room

6 cycles
Credit leak: count drifts down while the buffer has roomconserved (8 = 8)conserved(8 = 8)leaking: sum < grantedleaking: sum < grantedavail+in_flight < granted: leakavail+in_flight < granted:leakcount drifting toward stallcount drifting toward stallCLKgranted888888available433221in_flight444444avail+flight877665leak011111t0t1t2t3t4t5
Figure 2 — the waveform signature of a credit leak. The granted total is constant, but the sender's available credits drift downward while the receiver's buffer occupancy does not account for them — available plus in-flight falls below granted, so credits have leaked. The leak signal marks where conservation is first violated. The buffer is not full, yet the count decays.

The signature is avail+flight falling below granted (8) — conservation is broken — while in_flight shows the buffer is not full. The leak signal marks where the sum first drops. A credit count drifting down with a non-full buffer is a leak, not backpressure (where the sum would stay at 8 with in_flight rising to fill it).

9. Diagnosis Path

The methodical conservation check.

StepActionWhat it finds
1. Symptoma sender stalls; channel throughput decayssuspect a credit issue
2. Buffer stateis the receiver buffer full or has room?leak (room) vs backpressure (full)
3. Conservationcompute available + in-flight vs grantedequal (ok) or short (leak)
4. Onsetwhen the sum first dropped below grantedthe leak's onset
5. The eventwhich slot free did not return a creditthe leaking event
6. Root causemissing return, double-consume, or lost flitthe accounting bug (14.1)

The rule to carry: conservation distinguishes a leak from a stall. A stalled sender is ambiguous — it could be benign backpressure (buffer full) or a leak (buffer empty). The conservation check disambiguates: under backpressure, granted = available + in-flight still holds (the credits are all in-flight); under a leak, the sum is short (a credit vanished). Once you see the shortfall, trace to the slot free that failed to return a credit — the accounting bug — and the drift stops.

10. Tracing a Credit Leak — a worked trace

A channel's sender stalls and its throughput decays to zero over time, though the receiver is idle.

  1. Symptom: decaying throughput. The sender sends fewer and fewer flits over time until it stops — yet the receiver's buffer is mostly empty.
  2. Buffer has room. The receiver's buffer occupancy is low — it is not applying backpressure. So the stall is not legitimate; suspect a leak.
  3. Check conservation. Grant = 8. Over time, available drifts to 1 while in-flight is 4 — sum = 5, short of 8 by 3. Three credits have leaked.
  4. Find the onset. The sum first dropped below 8 at a specific event — a slot free at the receiver.
  5. The leaking event. At that free, the receiver processed a flit and freed the slot but did not send a credit return — so a credit vanished (the Chapter 14.1 bug). It happened again on later frees.
  6. Root cause and fix. The receiver's credit-return logic misses a slot-free case (a return not issued). Fix it to return a credit on every slot free; conservation holds and the drift stops.

The decaying throughput traced through the conservation shortfall to a missing credit return. The DebugLab formalizes this.

11. Detector View — a credit-conservation detector

Check that available plus in-flight equals granted; flag a leak when the sum is short. Representative.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Representative credit-conservation detector (educational).
// Credits are conserved: granted == available (at sender) + in_flight (slots occupied at
// receiver). A credit consumed on a send must be returned on a slot free. When
// available + in_flight < granted, a credit has LEAKED (freed without returning, or lost).
module chi_credit_leak #(parameter W = 8) (
  input  logic [W-1:0] granted,     // total credits granted (constant)
  input  logic [W-1:0] available,   // credits the sender currently holds
  input  logic [W-1:0] in_flight,   // credits spent on flits still occupying slots
  output logic [W:0]   accounted,   // available + in_flight (should equal granted)
  output logic         leak,         // conservation broken -> a credit leaked
  output logic [W:0]   leaked_count  // how many credits leaked
);
  assign accounted    = available + in_flight;
  // A leak: fewer credits accounted for than were granted.
  assign leak         = (accounted < granted);
  assign leaked_count = (accounted < granted) ? (granted - accounted) : '0;
endmodule

The same behavior in Verilog-2001:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Representative credit-conservation detector (Verilog-2001).
module chi_credit_leak #(parameter W = 8) (
  input  [W-1:0] granted, available, in_flight,
  output [W:0]   accounted,
  output         leak,
  output [W:0]   leaked_count
);
  assign accounted    = available + in_flight;
  assign leak         = (accounted < granted);
  assign leaked_count = (accounted < granted) ? (granted - accounted) : {(W+1){1'b0}};
endmodule

And in VHDL:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- Representative credit-conservation detector (VHDL).
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
entity chi_credit_leak is
  generic ( W : integer := 8 );
  port (
    granted      : in  unsigned(W-1 downto 0);
    available    : in  unsigned(W-1 downto 0);
    in_flight    : in  unsigned(W-1 downto 0);
    accounted    : out unsigned(W downto 0);
    leak         : out std_logic;
    leaked_count : out unsigned(W downto 0)
  );
end entity;
 
architecture rtl of chi_credit_leak is
  signal acc : unsigned(W downto 0);
begin
  acc          <= resize(available, W+1) + resize(in_flight, W+1);
  accounted    <= acc;
  leak         <= '1' when acc < resize(granted, W+1) else '0';
  leaked_count <= (resize(granted, W+1) - acc) when acc < resize(granted, W+1)
                  else (others => '0');
end architecture;

All three compute accounted = available + in_flight and flag leak when it is less than granted, reporting the leaked count. Bind it to a channel's credit signals and it fires the instant conservation breaks — at the leaking slot-free, not the far-later stall. The DebugLab's leak is a missing credit return.

12. Assertion View — credits are conserved

The properties formalize the invariant: available plus in-flight always equals granted.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Bind to chi_credit_leak.
// 1. Credits are conserved: available + in_flight always equals granted.
property p_credits_conserved;
  @(posedge clk) disable iff (!rst_n)
    (available + in_flight == granted);
endproperty
 
// 2. A leak is flagged exactly when the accounted total is short.
property p_leak_iff_short;
  @(posedge clk) disable iff (!rst_n)
    leak == (available + in_flight < granted);
endproperty
 
// 3. The accounted total never EXCEEDS granted (that would be a double-return bug).
property p_no_over_credit;
  @(posedge clk) disable iff (!rst_n)
    (available + in_flight <= granted);
endproperty

The system point, beyond the checks:

A conservation law is the most powerful kind of invariant a debugger can have, because it is checkable at every instant from a small amount of state and it localizes in time the exact moment the law breaks. Credits are a conserved quantity — granted is constant, and available + in_flight must equal it forever — so any deviation is a bug at the cycle it appears, no matter where the far-away symptom (a stall) shows up. This is the same shape as the dirty-data conservation of Chapter 18.1: identify the conserved quantity, express it as an equality that must always hold, and a violation points at the transaction that broke it. The two failure directions are both caught: available + in_flight < granted is a leak (a credit vanished — a missing return or lost flit), and available + in_flight > granted is an over-credit (a credit was returned twice or spuriously — which is worse, because it lets the sender overflow the receiver, Chapter 14.1's original bug). So the single conservation equality catches both the stall-causing leak and the overflow-causing double-return. The general debugging lesson, recurring through this module, is to find the system's conservation laws — dirty data, credits, ownership — and monitor them as equalities, because they turn a distant, confusing symptom into a precise, time-localized violation.

  • What it proves: credits are conserved (sum equals granted); leaks and over-credits are flagged.
  • What it does not prove: the grant matches the real buffer capacity — a design-time obligation (14.1).
  • Bug signature: available + in_flight != granted — short (leak) or over (double-return).

13. Testbench — a leaked credit must break conservation

Leaks credits (sum falls below granted) and checks the detector flags it, distinguishing from backpressure.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
module tb_chi_credit_leak;
  localparam W = 8;
  logic [W-1:0] granted, available, in_flight;
  logic [W:0] accounted, leaked_count;
  logic leak;
  int errors = 0;
 
  chi_credit_leak #(.W(W)) dut (.*);
 
  initial begin
    granted = 8;
 
    // CONSERVED (backpressure): buffer full -> in_flight=8, available=0, sum=8. NOT a leak.
    available = 0; in_flight = 8; #1;
    if (leak) begin errors++; $display("FAIL backpressure flagged as leak"); end
    else $display("PASS full buffer (backpressure): conserved, no leak (sum=%0d)", accounted);
 
    // CONSERVED (normal): available=5, in_flight=3, sum=8. No leak.
    available = 5; in_flight = 3; #1;
    if (leak) begin errors++; $display("FAIL normal state flagged as leak"); end
    else $display("PASS normal: conserved (sum=%0d = granted)", accounted);
 
    // LEAK: available=1, in_flight=4, sum=5 < 8 -> 3 credits leaked (buffer has room!).
    available = 1; in_flight = 4; #1;
    if (!leak) begin errors++; $display("FAIL leak NOT detected"); end
    else if (leaked_count !== 3) begin errors++; $display("FAIL wrong leaked count: %0d", leaked_count); end
    else $display("PASS leak detected: %0d credits leaked (sum=%0d < granted=8)", leaked_count, accounted);
 
    if (errors == 0) $display("ALL TESTS PASSED");
    else             $display("%0d FAILURE(S)", errors);
    $finish;
  end
endmodule

Expected output:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
PASS full buffer (backpressure): conserved, no leak (sum=8)
PASS normal: conserved (sum=8 = granted)
PASS leak detected: 3 credits leaked (sum=5 < granted=8)
ALL TESTS PASSED

14. DebugLab — a channel's throughput decaying to a stall

1

A channel's throughput decaying to a stall

SENDER STALLS WITH AN EMPTY RECEIVER -> CREDITS LEAK (SLOT FREED WITHOUT RETURNING A CREDIT) -> CONSERVATION BROKEN
Symptom

A channel's throughput decays over time until the sender stalls completely, yet the receiver's buffer is mostly empty — it is not applying backpressure. Other channels are fine. The decay is gradual and monotonic, distinguishing it from a sudden freeze.

Evidence

The conservation check comes up short:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
symptom: sender throughput decays to 0; receiver buffer LOW (not full) -> not backpressure
step 3 - conservation: granted = 8; over time available = 1, in_flight = 4
  -> available + in_flight = 5 < granted 8  -> 3 credits LEAKED
step 4/5 - onset: sum first fell below 8 at a receiver SLOT-FREE event
  -> receiver freed a slot but did NOT send a credit return -> credit vanished
  -> repeated frees without returns drove available -> 0 -> permanent stall
correct: return a credit on EVERY slot free -> sum stays = 8 -> no drift

The buffer had room, but the sender had no credits — because credits leaked.

First Divergence

A receiver slot-free event failed to return its credit — the first cycle available + in-flight fell below granted. Each subsequent missed return leaked another credit, drifting the sender's count toward zero.

Root Cause

Credits are a conserved quantity — granted equals available plus in-flight — so a credit leak (a slot freed without returning a credit, or a lost return) breaks conservation and drifts the sender's count down to a permanent stall while the receiver has room. The stall looks like backpressure but is not: under backpressure conservation holds (all credits are in-flight, buffer full); under a leak the sum is short (a credit vanished, buffer empty). The conservation equality distinguishes them and localizes the leak to the slot-free that missed its return — a Chapter 14.1 accounting bug (a return not issued on freeing a slot). The same equality catches the opposite bug too: an over-count (double-return) that would let the sender overflow the receiver. Monitor the conservation law as an equality.

Fix

Return a credit on every slot free — as Chapter 14.1's accounting requires — so credits are conserved and granted = available + in-flight always holds. The sender's count stops decaying and throughput recovers. Confirm with the detector that the accounted total never falls below (leak) or rises above (double-return) the grant. Conserve credits exactly.

15. Common Mistakes

  • Mistaking a leak for backpressure. Assumption: a stalled sender means a full buffer. Bug: the buffer is empty. Prevention: check conservation.
  • Not conserving credits. Assumption: returns are best-effort. Bug: drift to a stall. Prevention: return on every slot free.
  • Missing a slot-free case. Assumption: all frees return a credit. Bug: a leaking path. Prevention: audit every free.
  • Double-returning a credit. Assumption: extra returns are safe. Bug: over-credit, overflow. Prevention: one return per free.
  • Ignoring the drift. Assumption: throughput is just low. Bug: a slow leak. Prevention: watch the count trend.
  • Confusing with deadlock. Assumption: same frozen fabric. Bug: flow-control vs cycle. Prevention: 18.6 is a cycle; 18.7 is conservation.

16. Engineering Checklist

  • On a stalled sender, check if the receiver buffer has room (leak) or is full (backpressure).
  • Compute credit conservation — available + in-flight vs granted.
  • Flag a leak when the sum is short, an over-credit when it is over.
  • Find the onset — the slot free that missed its credit return.
  • Return a credit on every slot free; never double-return.
  • Watch the sender's credit count for a downward drift.

17. Key Takeaways

  • A credit leak is credits consumed but never returned — the count drifts down.
  • The symptom is a sender stalling while the receiver has room.
  • It is not backpressure — under backpressure the buffer is genuinely full.
  • The signature is a credit count drifting down monotonically.
  • Diagnose by conservationgranted = available + in-flight.
  • Conserve credits exactly; the model here is representative.

18. Quick Revision

Credit issues. Credit-based flow control (Chapter 14.1) depends on a conservation law: every credit consumed on a send must be returned when the receiver frees the slot, so granted = available + in-flight holds forever. A credit leak breaks it — a slot freed without returning a credit, or a lost return flit — so the sender's available count drifts down over time until it hits zero and the sender stalls permanently, even though the receiver's buffer has room and throughput on the channel decays. The trap is that this looks like backpressure, but it is the opposite: under backpressure the buffer is genuinely full (all credits in-flight, sum still = granted) and the stall resolves; under a leak the buffer is empty (sum short) and the stall is permanent. The distinguishing signature is a credit count drifting down while the receiver has free slots. The diagnosis is the conservation check: available + in-flight vs grantedshort means a leak, over means a double-return (which lets the sender overflow, the original 14.1 bug). Trace the shortfall to the slot free that missed its credit return — the accounting bug — and fix it to return a credit on every free. A conservation law turns a distant stall into a time-localized violation. Representative model; 18.8 debugs ordering violations.

Coming Next

Chapter 18.8 — Ordering Violations. A credit issue starves a channel; an ordering violation delivers events in a forbidden order. Chapter 18.8 covers ordering violations — events observed in an order the protocol forbids, the signature of two events with the wrong relative timing, and the diagnosis of checking each required precedence to find the ordering constraint that was not enforced.