Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • How to Use This Course
  • Reading Paths
  • Concept Map
  • How to Read the Diagrams
  • Part 0: What Is a Protocol?10
  • Part 1: Timing and Clocking11
  • Part 2: Encoding and Framing12
    • Line Codes
    • Framing Basics
    • Packet Anatomy
    • Bit Stuffing
    • DC Balance and Running Disparity
    • Block Codes
    • Scrambling
    • Alignment and Lock
    • Control Symbols and Ordered Sets
    • Flits, Phits and Packing
    • Protocols Compared: Encoding and Framing
    • Drills: Encoding and Framing
  • Part 3: Handshakes13
  • Part 4: Flow Control17
  • Part 5: Transactions19
  • Part 6: Concurrency and Performance17
  • Part 7: Ordering13
  • Part 8: Sharing and Arbitration12
  • Part 9: Deadlock and Liveness13
  • Part 10: Reliability and Recovery20
  • Part 11: Bring-Up and Link Management10
  • Part 12: Power8
  • Part 13: Shared State and Coherence9
  • Part 14: Security and Isolation7
  • Part 15: Specifying and Verifying11
  • Part 16: Protocols Dissected17
  • Part 17: Capstones5
  • Part 18: Interview Preparation6
Loading lesson

‹Part 2: Encoding and Framing
  1. Topics
  2. First Principles of Hardware Protocols
  3. Part 2: Encoding and Framing
  4. Scrambling

Part 2 · Encoding and Framing · Working (W)

Scrambling

XOR the data with a pseudo-random sequence so any data looks random on the wire. Additive versus self-synchronising scramblers, and how both ends stay in step.

On this page

    Note

    Level: Working (W) · Answers: Where does a message start and end?

    Before this: Block Codes

    A link with 1.5% coding overhead carries a long stretch of zero bytes, the most common content in memory and files. On the wire, those zeros must still produce transitions every few bits and stay roughly balanced, with no 8b/10b table to enforce it. The block code adds only two header bits per 128. Something else must make zeros look busy.

    How can a link make any data look random on the wire, and still deliver it unchanged?

    The obvious answer, and why it breaks

    One obvious idea is to invert every other bit, which turns long runs of zeros into alternating patterns. But some data, alternating bits for example, then turns into long runs. Any fixed, simple transformation maps some common pattern onto a bad one. The transformation must be one that no realistic data pattern can line up with, which means it must look random, while both ends can still reproduce it exactly.

    The idea: XOR with a sequence both ends can generate

    A scrambler XORs each data bit with the next bit of a pseudo-random sequence: a sequence that looks random but is generated by a small, deterministic circuit, usually a linear-feedback shift register (LFSR). The receiver generates the same sequence and XORs again; since x XOR s XOR s = x, the data comes back exactly. Long runs and imbalance in the data become, on the wire, the sequence's own pattern, which has plenty of transitions and is balanced on average.

    There are two ways to keep the receiver's sequence in step with the transmitter's:

    Type

    How the sequence is generated

    Keeping in step

    Error behaviour

    Additive (frame-synchronous)

    The LFSR runs on its own, independent of the data

    Both LFSRs must start from the same state at the same moment: the protocol resets or resynchronises them at known points

    A bit error on the wire stays one bit error

    Self-synchronising (multiplicative)

    The LFSR is fed by the scrambled bits themselves

    Automatic: after as many bits as the register is long, the receiver's register holds the same scrambled bits as the transmitter's

    One bit error on the wire becomes several errors after descrambling (one per tap), which the CRC must catch

    Both LFSRs start from the same seed and step together, so the second XOR cancels the first.

    Build it: an additive scrambler and descrambler

    The listing uses a 7-bit LFSR with polynomial x⁷ + x⁶ + 1, a common test-pattern generator, at both ends. The data is sixteen zeros followed by a few ones and zeros. A checker confirms the descrambled output equals the input and counts transitions in the data and on the line during the run of zeros.

    lfsr7.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    // Additive scrambling with a 7-bit LFSR (polynomial x^7 + x^6 + 1, a common test
    // pattern generator). The transmitter XORs each data bit with the LFSR's output; the
    // receiver runs an identical LFSR from the same seed and XORs again, which restores
    // the data. A long run of zeros in the data becomes a busy pattern on the line.
    module lfsr7 (input logic clk, input logic rst_n, output logic out);
      logic [6:0] s;
      assign out = s[6];
      always_ff @(posedge clk or negedge rst_n)
        if (!rst_n) s <= 7'h24;                         // seed: any non-zero value works
        else        s <= {s[5:0], s[6] ^ s[5]};         // taps for x^7 + x^6 + 1
    endmodule
    
    module tb;
      logic clk = 0;
      always #5 clk = ~clk;
      logic rst_n = 0;
      initial begin
        $dumpfile("wave.vcd"); $dumpvars(0, tb);
        #12 rst_n = 1;
      end
    
      // Data: sixteen zeros, then a few ones and zeros.
      localparam logic [23:0] DATA = 24'b1010_0110_0000_0000_0000_0000;
      int  i = 0;
      always @(posedge clk) if (rst_n && i < 23) i <= i + 1;
      wire din = DATA[i];
    
      wire prbs_tx, prbs_rx;
      lfsr7 tx_lfsr (.clk, .rst_n, .out(prbs_tx));
      lfsr7 rx_lfsr (.clk, .rst_n, .out(prbs_rx));    // same seed, same clock: in lockstep
      wire line = din ^ prbs_tx;                      // what travels on the wire
      wire dout = line ^ prbs_rx;                     // descrambled at the receiver
    
      int errors = 0, din_edges = 0, line_edges = 0;
      logic din_q, line_q;
      always @(posedge clk) if (rst_n) begin
        if (dout != din) errors++;
        if (i > 0 && i <= 16) begin din_edges += (din != din_q); line_edges += (line != line_q); end
        din_q <= din; line_q <= line;
      end
      initial begin
        #250;
        if (errors == 0)
          $display("PASS: data recovered exactly; during the zero run the data had %0d transitions, the line %0d", din_edges, line_edges);
        else $display("FAIL: %0d errors", errors);
        $finish;
      end
    endmodule

    Watch it run

    How to read it, slot by slot:

    • Slots 0 to 15: din is all zeros, a run with no transitions at all. prbs_tx is the LFSR's output, and since 0 XOR s = s, line equals the sequence: it changes level eleven times in those sixteen slots.

    • Slots 16 to 21: din carries some ones and zeros. line is now din XOR the sequence, and no longer equals either.

    • Every slot: dout equals din exactly, because the receiver's LFSR produced the same sequence and the second XOR cancelled the first.

    This tiny LFSR repeats every 127 bits and can produce runs of up to seven identical bits; real links use much longer registers whose sequences repeat after billions of bits.

    What scrambling does not do

    • It gives no hard guarantee. Data that happens to equal the scrambling sequence becomes all zeros on the wire. Such patterns are vanishingly rare in real traffic but can be constructed on purpose. Protocols therefore pair scrambling with something unconditional, such as a sync header that always contains a transition.

    • It is not encryption. The sequence is public and short-lived; anyone can descramble.

    • It does not mark boundaries. The receiver must already know where blocks start (lesson 2.8), which is why sync headers are left unscrambled.

    The design space

    Choice

    Trade-off

    Additive vs self-synchronising

    Additive: no error multiplication, but the protocol must resynchronise both ends. Self-synchronising: no resync needed, but each line error becomes several data errors.

    LFSR length

    Longer registers repeat less often and look more random; cost is a few more flip-flops (per lane, and per parallel bit in wide datapaths)

    What to leave unscrambled

    Headers and control fields the receiver needs before it can descramble

    How real protocols chose

    Protocol

    Scrambling

    10 Gb/s Ethernet (64b/66b)

    A self-synchronising scrambler with polynomial 1 + x³⁹ + x⁵⁸ over the 64-bit payload; the 2-bit sync header is not scrambled, so each block's header always delivers a transition.

    PCI Express Gen3–5 (128b/130b)

    Scrambled data blocks with an unscrambled 2-bit sync header.

    The 64b/66b choice of a self-synchronising scrambler avoids any resynchronisation protocol, and its error multiplication (each line error becomes three data errors, one per tap and the original) is covered by the frame's CRC.

    What breaks

    A link's two ends reset their additive scramblers at slightly different times after a link restart (illustrative): the transmitter at the end of training, the receiver one block later. The two sequences are now one block apart, so every descrambled bit is data XOR s(n) XOR s(n − 128), which is garbage. Every block fails its CRC, and the link retrains forever.

    • Symptom: the link trains, then fails every packet, then retrains.

    • Root cause: the additive scramblers were not synchronised at the same symbol.

    • Fix: define the exact point at which both ends reset or resynchronise the LFSR, and check it in a test that restarts the link many times.

    Why this matters

    Senior lens. Scrambling is the cheapest way to get transitions and balance, so it is the default at high rates, but it moves risk into two places worth reviewing: synchronisation of additive scramblers (when exactly do both ends reset?) and the guarantees that must not depend on it (headers, alignment, worst-case wander). For self-synchronising scramblers, check that the error-detection code was chosen knowing that every line error arrives as a small burst.

    Interview

    Asked: "Does scrambling guarantee transitions?"

    Weak answer: Yes, it randomises the data.

    Strong answer: No, only statistically. A scrambler XORs data with a pseudo-random sequence, so real data almost never produces long runs, but data equal to the sequence would become a constant. That's why 64b/66b and 128b/130b keep a 2-bit sync header, always 01 or 10, unscrambled: it guarantees at least one transition per block. Scrambling also doesn't mark boundaries or encrypt anything.

    Follow-ups: (1) Additive or self-synchronising: what are the trade-offs? (2) Why does a self-synchronising descrambler multiply errors?

    Check yourself In the waveform, why does line equal prbs_tx during the run of zeros?

    Because 0 XOR s = s: with zero data, the line carries the scrambling sequence itself.

    Check yourself Why does a self-synchronising descrambler turn one line error into several data errors?

    Its register is fed by received scrambled bits, so a wrong bit sits in the register and corrupts the output once for each tap it passes, in addition to the original position.

    Check yourself Why must the sync header be left unscrambled?

    The receiver uses it to find block boundaries before it can descramble, and its guaranteed transition must not depend on the scrambler.

    Key takeaways

    • A scrambler XORs data with a pseudo-random LFSR sequence; the receiver XORs with the same sequence to recover it.

    • Additive scramblers need both ends resynchronised; self-synchronising ones resynchronise themselves but multiply errors.

    • Scrambling is statistical, not a guarantee, not encryption, and not framing; pair it with unscrambled headers.

    Keep going

    Next: Lesson 2.8, Alignment and Lock. How a receiver finds block boundaries in a raw bit stream, and how it notices when it has lost them.

    Related topics

    • Part 2 overview: Encoding and Framing

    Previous

    32 / 234

    Next: Alignment and Lock

    Up next

    Up nextAlignment and Lock

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Line Codes
    • Framing Basics
    • Packet Anatomy
    clkdinprbs_txlinedout
    Simulation output: a run of zeros in din becomes a busy pattern on the line; dout equals din. One slot is one bit.