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
    • Common-Clock Interfaces
    • Asynchronous Serial and Oversampling
    • Source-Synchronous Clocks and Strobes
    • Embedded Clocks and Clock Recovery
    • Skew and Deskew
    • Clock Relationships
    • Elastic Buffers and Clock Compensation
    • Self-Timed Handshakes
    • Crossing at the Interface
    • Protocols Compared: Timing and Clocking
    • Drills: Timing and Clocking
  • Part 2: Encoding and Framing12
  • 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 1: Timing and Clocking
  1. Topics
  2. First Principles of Hardware Protocols
  3. Part 1: Timing and Clocking
  4. Skew and Deskew

Part 1 · Timing and Clocking · Working (W)

Skew and Deskew

A wide serial link splits each word across lanes that arrive at different times. An alignment marker sent on every lane at once lets the receiver line them up again.

On this page

    Note

    Level: Working (W) · Answers: When is the data valid?

    Before this: Embedded Clocks and Clock Recovery

    A four-lane serial link sends each 32-bit word as four bytes, one per lane, in the same cycle. At the receiver each lane recovers its own clock and delivers its bytes perfectly, yet the reassembled words are scrambled: byte 0 of word 5 sits next to byte 1 of word 3. Every lane is right; together they are wrong.

    When each lane arrives at its own time, how does the receiver know which bytes belong together?

    The obvious answer, and why it breaks

    The obvious answer is to route the lanes with equal lengths so they arrive together. Matching helps, but it cannot be exact: connectors, cables, package routing and the receivers' own recovered clocks each add different delays, and at high rates even a few millimetres of difference is a whole bit. Worse, each lane's CDR may lock at a different point in its first word. The skew between lanes is unknown until the link is running, so it has to be measured, not designed away.

    The idea: send a marker on every lane at once

    The transmitter periodically sends a special alignment marker on all lanes in the same cycle, something the receiver can recognise and that never appears in normal data. Each lane's receiver notes when its marker arrives and buffers its data from that point on. When every lane has seen its marker, the receiver reads all the lane buffers together. Bytes that left together come out together, however late each lane was.

    The buffers absorb the difference: the earliest lane waits in its buffer for the latest one. So each lane's buffer must be at least as deep as the largest skew the link must tolerate, in cycles.

    The same picture as the simulation below: lanes delayed by 0, 1, 2 and 3 cycles; the output starts when the slowest lane's marker arrives.

    Build it: a four-lane deskew

    The testbench splits words across four lanes and sends a marker byte BC on every lane in one cycle, then six words. The channel delays the lanes by 0, 2, 1 and 3 cycles. The receiver writes each lane into its own small buffer from its marker onwards and reads all four with one shared read pointer once every lane has seen its marker. A checker confirms the six words come out whole and in order.

    tb.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
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    // Lane deskew with an alignment marker. A word is split across four lanes, one byte
    // per lane per cycle. The transmitter sends a marker byte (BC) on every lane in the same
    // cycle, then data. The lanes arrive with different delays (0, 2, 1 and 3 cycles). Each
    // lane writes into its own small buffer starting at its marker; once every lane has
    // seen its marker, all buffers are read together with one read pointer, so the bytes
    // that left together come out together.
    module tb;
      localparam logic [7:0] MARK = 8'hBC;
      logic clk = 0;
      always #5 clk = ~clk;
      logic rst_n = 0;
      initial begin
        $dumpfile("wave.vcd"); $dumpvars(0, tb);
        #12 rst_n = 1;
      end
    
      // Transmitter: idle (00), one cycle of markers, then words 0..5; lane i carries byte 4k+i+0x10.
      logic [3:0] t = 0;
      always @(posedge clk) if (rst_n && t != 4'd15) t <= t + 1;
      function automatic logic [7:0] tx_byte(input int lane, input logic [3:0] tt);
        if (tt == 2) return MARK;
        if (tt >= 3 && tt <= 8) return 8'h10 + 4 * (tt - 3) + lane;
        return 8'h00;
      endfunction
    
      // Channel: lane i delayed by DLY[i] cycles.
      localparam int D0 = 0, D1 = 2, D2 = 1, D3 = 3;
      logic [7:0] pipe [0:3][0:3];
      initial for (int l = 0; l < 4; l++) for (int k = 0; k < 4; k++) pipe[l][k] = 8'h00;
      logic [7:0] in0, in1, in2, in3;        // bytes arriving at the receiver, per lane
      always @(posedge clk)
        for (int l = 0; l < 4; l++) begin
          pipe[l][0] <= tx_byte(l, t);
          for (int k = 1; k < 4; k++) pipe[l][k] <= pipe[l][k-1];
        end
      assign in0 = pipe[0][D0];
      assign in1 = pipe[1][D1];
      assign in2 = pipe[2][D2];
      assign in3 = pipe[3][D3];
      logic [7:0] lane_in [0:3];
      always @* begin lane_in[0] = in0; lane_in[1] = in1; lane_in[2] = in2; lane_in[3] = in3; end
    
      // Receiver: per-lane buffer written from the marker on; one shared read pointer.
      logic [7:0] mem [0:3][0:7];
      logic [3:0] seen = 0;
      logic [2:0] wp [0:3];
      logic [2:0] rp = 0;                    // saturates at 7: the six words have been read
      initial for (int l = 0; l < 4; l++) wp[l] = 0;
      wire        aligned = &seen;
      always @(posedge clk) if (rst_n) begin
        for (int l = 0; l < 4; l++) begin
          if (!seen[l] && lane_in[l] == MARK) begin
            seen[l] <= 1; mem[l][0] <= MARK; wp[l] <= 1;
          end else if (seen[l]) begin
            mem[l][wp[l]] <= lane_in[l]; wp[l] <= wp[l] + 1;
          end
        end
        if (aligned && rp != 3'd7) rp <= rp + 1;
      end
      wire [31:0] out = aligned ? {mem[3][rp], mem[2][rp], mem[1][rp], mem[0][rp]} : 32'h0;
    
      // Checker: after the marker word, words 0..5 must come out whole and in order.
      function automatic logic [31:0] expected(input int k);
        logic [7:0] b0, b1, b2, b3;
        b0 = 8'h10 + 4 * k; b1 = b0 + 1; b2 = b0 + 2; b3 = b0 + 3;
        return {b3, b2, b1, b0};
      endfunction
      int errors = 0, words = 0;
      always @(posedge clk) if (aligned && rp != 3'd7) begin
        if (rp == 0 && out != {4{MARK}}) errors++;
        if (rp >= 1 && rp <= 6) begin
          if (out != expected(rp - 1)) errors++;
          words++;
        end
      end
      initial begin
        #200;
        if (errors == 0 && words == 6) $display("PASS: lanes skewed by 0, 2, 1 and 3 cycles realigned; 6 words intact");
        else $display("FAIL: %0d errors, %0d words", errors, words);
        $finish;
      end
    endmodule

    Watch it run

    How to read it, slot by slot:

    • Slots 3 to 6: the marker bc arrives on lane 0 in slot 3, lane 2 in slot 4, lane 1 in slot 5 and lane 3 in slot 6. The bytes after each marker belong to the same words, but they arrive staggered.

    • Slots 4 to 7: seen collects one bit per lane as markers arrive: 1, 5 (lanes 0 and 2), 7, then f in slot 7 when the slowest lane has its marker.

    • Slot 7: with every lane aligned, the shared read pointer (rp) starts at 0, and out shows the four markers together: bcbcbcbc.

    • Slots 8 to 13: out delivers words 0 to 5 whole: 13121110 is bytes 10, 11, 12 and 13 from lanes 0 to 3, which left the transmitter in the same cycle and arrived up to three cycles apart.

    • Slot 14: after the six words, rp stops at 7 and the output goes idle.

    Lane 0's bytes waited three cycles in its buffer; lane 3's waited none. The buffers turned an unknown skew into a fixed latency equal to the worst lane's delay.

    Worked numbers: how deep the buffers must be

    Skew is set by physical differences, so it is fixed in time, while the bit time shrinks with rate. With illustrative numbers:

    Diagram
    Lane-to-lane skew to tolerate: 2 ns (cables, connectors, packages, receivers)
    
    At  2.5 Gb/s per lane: bit = 400 ps  -> skew =  5 bits
    At 16   Gb/s per lane: bit = 62.5 ps -> skew = 32 bits
    
    With 32-bit words per lane per cycle, 32 bits of skew is one word of buffering per lane,
    plus a margin: the buffer depth grows with the rate even though the skew does not.

    The design space

    Choice

    What it costs

    When it wins

    Tight length matching only

    Routing effort; no tolerance for anything unmatched

    Short, slow, parallel links

    Alignment markers + per-lane buffers (this lesson)

    Marker bandwidth; buffer per lane; latency equal to the worst skew

    Multi-lane serial links: the standard answer

    Train once at start-up, then hold

    Must retrain if skew drifts

    Links whose skew is stable once warm

    Markers repeated periodically

    A little more overhead

    Links that must also detect or recover from lane slips while running

    How real protocols chose

    Protocol

    Its choice

    PCI Express

    Links have 1 to 32 lanes, each with its own recovered clock. The receiver must remove lane-to-lane skew, using ordered sets that the transmitter sends on all lanes at the same time as alignment points.

    DDR memory

    Not serial, but the same problem: each data group has its own strobe, so skew only has to be controlled within a group, and the controller trains each group's capture timing separately.

    What breaks

    A design sizes its deskew buffers for the skew of the reference board (illustrative). A customer uses a longer cable whose pairs differ more in length, and the worst lane arrives one word later than the buffer can hold. The receiver then aligns the lanes one word apart: every reassembled word mixes bytes from two different words, but each lane's data is perfect and each lane reports no errors.

    • Symptom: link trains, lanes report clean, but upper-layer data is garbled.

    • Evidence: markers on one lane are detected a word later than the deskew logic allows.

    • Fix: deeper buffers sized from the specification's skew limit, not the bench; and a check that flags "marker outside the window" instead of silently misaligning.

    Why this matters

    Senior lens. Deskew converts an unknown skew into a known latency, so ask two questions in review. First, what is the maximum skew the specification promises to tolerate, and are the buffers sized for it at the highest rate? Second, what happens when the skew is beyond that: does the receiver detect it and refuse to train, or does it align wrongly and report success? Silent misalignment is the dangerous outcome, because every per-lane check passes.

    Interview

    Asked: "How does a x16 link line its lanes up?"

    Weak answer: The lanes are routed with the same length.

    Strong answer: Length matching only reduces skew. The transmitter sends a recognisable marker, an ordered set, on all lanes in the same cycle. Each lane's receiver buffers its data from where its marker arrived; once all lanes have their markers, it reads them together, so the earliest lanes wait for the latest. Buffer depth must cover the specified maximum skew at the highest rate, and the result is a fixed latency equal to the worst lane's delay.

    Follow-ups: (1) Why does buffer depth grow with the data rate? (2) What should happen if one lane's skew exceeds the buffer?

    Check yourself In the simulation, how many cycles did lane 0's bytes wait in its buffer, and why?

    Three: lane 0 had no channel delay and lane 3 had three, so lane 0 must wait for lane 3's matching bytes before a whole word can be output.

    Check yourself Why must the marker be something that never appears in normal data?

    So a lane cannot mistake a data byte for a marker and align on the wrong cycle. Protocols use control symbols or ordered sets for this (lesson 2.9).

    Check yourself Skew stays at 1.5 ns while the lane rate doubles. What happens to the deskew buffer?

    The skew in bits doubles, so the buffer, measured in bits or words, must double too.

    Key takeaways

    • Lane-to-lane skew comes from physical differences and recovered clocks; it is unknown until the link runs, so it must be measured.

    • A marker sent on every lane at once lets each lane buffer from its marker; reading all buffers together realigns the words.

    • Buffers must cover the specified maximum skew at the highest rate; exceeding them should be detected, never silently misaligned.

    Keep going

    Next: Lesson 1.6, Clock Relationships. Two clocks can be the same, related, nearly equal or unrelated. Each relationship needs a different crossing.

    Related topics

    • Part 1 overview: Timing and Clocking

    • Lesson 1.4: Embedded Clocks and Clock Recovery

    Previous

    19 / 234

    Next: Clock Relationships

    Up next

    Up nextClock Relationships

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Common-Clock Interfaces
    • Asynchronous Serial and Oversampling
    • Source-Synchronous Clocks and Strobes
    clkin00bc1014181c20240in10bc1115191d21250in20bc12161a1e22260in30bc13171b1f23270seen0157frp01234567out0bcbcbcbc13121110171615141b1a19181f1e1d1c23222120272625240
    Simulation output: lanes arrive with different delays (in0 to in3); once seen = f (all four markers), out delivers whole words. One slot is one cycle.