Skip to content
VLSI Mentor

UART · Module 11

Loopback, Test Modes and Built-In Self-Check

Internal and line loopback, what each one proves, and — measured — the faults they provably cannot see. The cheapest RTL in the IP and the most decisive during bring-up.

A link that does not work presents as one symptom: nothing arrives. Behind that symptom are at least six candidates — the transmitter, the receiver, the baud generator, the pins, the wiring, and the far end — and a UART with no test modes gives you no way to eliminate any of them.

This chapter builds the features that partition that space. They are the cheapest RTL in the entire IP: two muxes, one extra port. They are also the only thing that turns a bring-up from guessing into bisection.

The discipline that matters most here is knowing what a passing test mode does not prove — so §3 breaks the receive pin and shows internal loopback passing anyway.

1. Two Loopbacks, Facing Opposite Directions

They are routinely confused because both are called "loopback". They test disjoint things.

Internal loopback connects this IP's transmitter to its own receiver, before the pins. It asks: do my engines work?

Line loopback connects the receive pin straight back to the transmit pin. It asks nothing about this IP at all — it lets the far end ask: does the path to that board and back work?

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Both loopbacks, complete. They face opposite directions and are
// independent; setting both is legal and is not a combinational loop,
// because rx_i is an input.
logic tx_line, rx_line;
assign tx_o    = cfg_line_loop_i ? rx_i    : tx_line;
assign rx_line = cfg_loopback_i  ? tx_line : rx_i;

That is the entire feature. Two ternaries. Everything else in this chapter is about what they let you conclude.

A block diagram showing the two loopback paths through the UART IP. The transmit engine drives an internal transmit line, which reaches the transmit pin and the outside world. The receive pin brings the line back to the receive engine. Internal loopback is a mux that feeds the internal transmit line back into the receive engine, bypassing both pins; it covers the transmit engine, the receive engine and the shared timing generator. Line loopback is a mux that feeds the receive pin directly to the transmit pin, bypassing both engines; it covers the receive pin, the transmit pin and the board wiring between them and the far end.TX enginequeue + shiftertiming genshared by bothRX enginesampler + shifterinternal loopcfg_loopback_iline loopcfg_line_loop_itx pinpad + board tracerx pinpad + board tracefar endcable, peer devicetx_linerx_linenormalnormalechoechotickswirewire12
Figure 1 — the two loopbacks and the region each one covers. Internal loopback closes the path inside the IP, so it exercises both engines and the shared timing generator while excluding the pins and the board. Line loopback closes the path at the pins, so it exercises the pins and the board while excluding both engines.

The transmit pin keeps driving during internal loopback — the mux feeds the receiver a copy of the line, it does not steal it. That is deliberate: the frames stay visible on an oscilloscope, so a self-test can be watched from outside. Measured: internal loopback: tx_o STILL drives the pin (scope-visible) — pass.

2. What Internal Loopback Proves

It exercises, in one measurement, nearly everything Modules 6 through 10 built:

CoveredBecause
transmit shift, framing, parity generationthe frame has to be well-formed to decode
receive sampling, start detection, parity checkit has to decode that frame
the shared timing generatorboth halves use the same ticks — Chapter 11.2 §2
both FIFOs and their handshakesthe bytes travel through them
the configured frame format end to endwrong parity shows as a parity error

The timing generator is the valuable one. A baud rate that is wrong by 10% still round-trips perfectly in internal loopback, because both halves are wrong identically — so loopback does not validate the baud rate. What it validates is that the tick distribution is coherent, which is a different and still useful claim.

3. The Fault Internal Loopback Cannot See

Reasoning about coverage is weaker than measuring it. So: break the receive pin — stuck at 0, a dead pad or a broken trace, entirely outside anything the IP can reach — and run internal loopback anyway.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  pass internal loopback: byte returns
  pass internal loopback: no errors
  pass RX PIN STUCK AT 0 : internal loopback STILL PASSES
      -> a dead receive pin is invisible to internal loopback

The byte round-trips perfectly over a receive pin that is physically dead, because rx_line is sourced from tx_line and never touches the pin. This is the correct behaviour and it is exactly the trap: a passing self-test on a board whose receive path is broken.

Which is precisely why line loopback exists, and why the pair is worth more than either alone:

internal loopbackline loopback
TX engine
RX engine
timing generator✅ (coherence only)
FIFOs
TX pin / pad
RX pin / pad
board wiring, connector, cable
absolute baud rate
far-end configuration

The two columns are almost perfectly complementary, which is the reason to build both. Line loopback was measured driving an external frame onto the receive pin with both engines uninvolved: line loopback: tx pin echoes the rx pin — pass.

Neither column covers baud rate or the far end. No test mode can: both are statements about a second device.

With the two modes, bring-up becomes a decision procedure rather than a search:

InternalLineNormalConclusion
IP and pins are fine — baud rate or far-end configuration
engines fine — pins, pads, or board wiring
the IP itself: clock, reset, timing generator, engines
working; if data is still wrong, it is format, not plumbing

Three tests, four conclusions, and each eliminates a region rather than guessing at a cause. The first row is the common one and the reason to check baud first when loopback passes.

5. Test Modes Worth Their Gates, and Ones That Are Not

The two loopbacks are unambiguously worth building. The rest of the usual list is more mixed:

Worth it — a forced break. One bit that holds tx_o low lets you generate a break on demand, which is the only way to test the far end's break handling without unplugging a wire. It costs one OR gate on the transmit output, and Chapter 9.4 §6 specified it.

Worth it — exposing cfg_pending_q. One status bit, and it converts "my configuration write did nothing" into "the change is queued and the link has not gone quiet" — Chapter 11.3 §3.

Worth it — a counter on received bytes and on errors. Cheap, and it turns "it is dropping data sometimes" into a rate.

Usually not worth it — an RTL pattern generator. A walking-ones self-test in hardware duplicates what software can do with a loop over the existing write port, and it must be maintained in RTL where changing it costs a re-synthesis. Build the loopback; let software supply the patterns.

Not worth it — a test mode that changes the datapath. Any mode that alters how data is processed rather than how it is routed creates a configuration in which the IP has never shipped. The two loopbacks here only re-route: every engine, FIFO and status path behaves identically in loopback and in normal operation, which is what makes a loopback result meaningful about normal operation.

6. Verification

Loopback is so useful as a test tool that it is easy to forget it is also logic that must be tested. Four properties matter:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Assertion — internal loopback must not disturb the transmit pin. The
// receiver takes a COPY; stealing the line would make self-test invisible
// to a scope and would silence the link the moment the mode is entered.
property p_loopback_keeps_tx_pin;
    @(posedge clk) disable iff (!rst_n)
        (cfg_loopback_i && !cfg_line_loop_i) |-> (tx_o == tx_line);
endproperty
assert property (p_loopback_keeps_tx_pin);

// Assertion — line loopback echoes the pin combinationally, whatever the
// engines are doing.
property p_line_loop_echoes;
    @(posedge clk) disable iff (!rst_n)
        cfg_line_loop_i |-> (tx_o == rx_i);
endproperty
assert property (p_line_loop_echoes);

// Assertion — with both modes off, neither path is engaged.
property p_no_mode_is_transparent;
    @(posedge clk) disable iff (!rst_n)
        (!cfg_loopback_i && !cfg_line_loop_i) |-> (tx_o == tx_line && rx_line == rx_i);
endproperty
assert property (p_no_mode_is_transparent);

The third is the one that protects production. It states that the test features are absent when not selected, which is the property every test mode must have and the one that a mux with a wrong polarity would break — in a way that only shows up on hardware, never in the loopback tests that were used to develop the feature.

Test that leaving a mode restores normal operation, not only that entering it works. Measured: line loop off: tx_o driven by the transmitter again — pass. A one-directional test passes on a mux that latches.

All three held for the entire run. And they were mutation-checked, because an assertion that has never failed is an assertion that might not be connected to anything: rewiring internal loopback to steal the transmit pin rather than copy it produced 8,680 assertion failures against zero on the real RTL.

The full result for this chapter's suite, including the broken-pin injection:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
== 13 checks, 0 failures ==

Routing, and what each mode can see

6 cycles
A trace of six phases comparing the loopback routings. In the first phase no mode is set and the transmit pin follows the transmit engine while the receive engine follows the receive pin, so the datapath is transparent. In the second and third phases internal loopback is enabled: the receive engine is fed from the internal transmit line, the transmit pin continues to be driven by the engine so the frames remain visible externally, and a byte is returned successfully. In the fourth phase the receive pin is forced stuck at zero while internal loopback remains enabled, and the byte still returns successfully because the receive path never touches the pin. In the fifth phase line loopback is enabled and the transmit pin echoes the receive pin directly with neither engine involved. In the final phase both modes are off and the transmit pin is once again driven by the transmitter.internal loopback — pins excludedinternal loopback — pinsexcludedtx pin still driving — scope-visibletx pin still driving —scope-visibledead pin, test still passesdead pin, test still passesengines uninvolvedengines uninvolvedphasenormalint loopint looprx pin brokenline loopnormalcfg_loopback_icfg_line_loop_itx_o sourceengineengineengineenginerx_ienginerx engine seesrx_itx_linetx_linetx_linerx_irx_ibyte returnedt0t1t2t3t4t5
Figure 2 — the same transmitted frame under each routing. Columns are the phases of one experiment, not clock cycles. With no mode set the pins are transparent. Internal loopback feeds the receiver a copy while the transmit pin keeps driving. With the receive pin broken, internal loopback is unaffected — the row that explains why a self-test can pass on a dead board. Line loopback echoes the pin with the engines uninvolved.

7. What This Means on an FPGA

Two 2:1 muxes on pin paths. One extra level of logic between the transmit register and the pad. On any FPGA this is noise against the pad delay itself, and it is worth knowing the level is there when reading a timing report for a fast link.

Bring up with internal loopback before the cable exists. It needs no peer, no external equipment and no correct baud rate — which means it can run on the first day the board powers on, and a pass eliminates the entire IP from the search.

Then check the bit period on a scope. Loopback cannot do it (§2), and it is the most common remaining fault. One measurement on tx_o, compared against Chapter 4.3's table.

Put line loopback behind a documented register bit and tell the far-end team it exists. Its whole value is to somebody debugging from the other end of the cable, and an undocumented test feature helps nobody.

Print the mode bits in the driver's diagnostic output. The failure mode of loopback is being left on, and it is indistinguishable from a broken link until somebody reads the register.

8. Understanding Check

9. Summary

Two ternaries and one extra port buy the ability to partition a dead link instead of guessing at it.

Internal loopback and line loopback face opposite directions and cover almost disjoint regions — engines and timing versus pins and board — which is why the pair is worth far more than either alone.

Neither can check the baud rate, because both halves share one generator and a wrong divisor cancels out. Loopback passing while the link is dead is the most common bring-up result, and it points at baud rate precisely because everything else has been eliminated.

A dead receive pin is invisible to internal loopback — measured, with the pin forced stuck at zero and the byte still returning intact. That is correct behaviour and exactly why the second mode exists.

A stuck-low pin is loud and a stuck-high pin is silent: one garbage byte, a framing error and a standing break, versus a trace indistinguishable from a healthy idle link.

Test modes must only re-route, never re-process, or a loopback result says nothing about normal operation. And the assertion that matters most is that with every mode off the datapath is transparent — the one property nothing else exercises, and the one whose failure ships.

10. What Comes Next

The IP is complete. Eleven blocks assembled, configuration plumbed and deferred, status aggregated, parameters checked at elaboration, and test modes to bring it up — verified by 53 integration checks, three parameter sets and a broken pin.

Everything remaining is about the world it has to live in. Module 12 takes the clock-domain question seriously: this IP assumes one clock, and a real SoC will not offer that — which brings genuine asynchronous FIFOs, reset methodology, timing constraints and synthesis signoff. Module 13 attaches it to a bus, and the register map, interrupts and DMA hooks this module deliberately kept out become the subject.

Browse the full path on the UART tutorials index. For the break behaviour a stuck-low pin triggers, read back to Chapter 9.4.

Continue learning

Where this fits

Part of the UART curriculum.