[CDC] 4_Multi Bit CDC: Handshake

2025. 12. 15. 00:59·VLSI/Design
728x90
반응형

이전 챕터에서는 2-FF Synchronizer, Pulse Stretching, Handshake, Toggle Synchronizer를 직접 설계하고 시뮬레이션을 통해 동작을 확인했다. 이번 챕터에서는 Multi-Bit CDC 방법 중 실무에서 가장 대표적으로 사용되는 Handshake 방식을 중심으로 살펴본다.

 

Multi-Bit CDC에서 2-FF를 쓰면 안 되는 이유

CDC의 핵심 목표를 다시 정리하면 다음 두 가지다.

  • Metastability의 격리
  • 신호/데이터 전달의 무결성 보장

2-FF Synchronizer는 이 중 메타안정성 완화만을 목적으로 한다. 즉, 메타안정 상태가 뒤쪽 로직으로 전파될 확률을 낮춰줄 뿐, 멀티비트 데이터의 무결성(coherence)이나 정합성(atomicity)은 전혀 보장하지 못한다.

따라서 멀티비트 데이터에 대해 각 비트마다 2-FF Synchronizer를 적용하는 방식은 구조적으로 잘못된 설계이며, 반드시 피해야 한다.

 

 

2-FF Synchronizer의 정확한 역할

2-FF Synchronizer의 목적은 단 하나다.

Metastability가 뒤 로직으로 퍼지는 것을 확률적으로 줄이는 것

 

이 때문에 2-FF는 다음과 같은 싱글 비트 제어 신호에만 사용된다.

  • enable
  • valid / ready
  • reset deassertion
  • 기타 단일 비트 control signal

 

Multi-Bit CDC의 진짜 문제: Metastability가 아니라 Bit 간의 Skew

멀티비트 CDC에서 가장 치명적인 문제는 Metastability 자체가 아니라 bit 간의 skew이다.

멀티비트 데이터의 각 비트는 서로 독립적으로 샘플링되며, 클럭 도메인이 다를 경우 다음과 같은 문제가 발생할 수 있다.

  • 어떤 비트는 이전 값으로 샘플링되고
  • 어떤 비트는 새로운 값으로 샘플링되며
  • 어떤 비트는 메타안정 상태에서 resolve됨

그 결과, 송신 도메인에서는 존재한 적 없는 데이터 조합이 수신 도메인에서 만들어질 수 있다.

이 문제는 메타안정성이 발생하지 않더라도 언제든지 발생 가능한 구조적인 문제이며, 단순한 2-FF Synchronizer로는 절대 해결할 수 없다.

 

멀티비트 CDC에서는 다음이 반드시 보장되어야 한다.

수신 클럭 도메인에서 멀티비트 데이터가 하나의 일관된 값으로 샘플링될 것

 

이를 위해서는 bit 간의 skew를 원천적으로 차단할 수 있는 CDC 구조가 필요하며, 그 대표적인 해법이 바로 Handshake 기반 Multi-Bit CDC이다. Toggle Synchronizer는 구조 상 멀티비트 CDC 처리가 불가능하며, Streching 방식은 유지보수의 이유로 사용하지 않는다.

 

 

 

Handshake CDC

 

Handshake CDC는 멀티비트 데이터 자체를 동기화하지 않고, 데이터가 안정적으로 유지되는 구간(stable window)을 명확히 만들어 수신 도메인이 그 구간에서 데이터를 샘플링하도록 하는 구조이다. 단순 Stretching과 유사해 보일 수 있지만, Handshake CDC는 두 클럭 도메인의 속도 비율이 어떠하든지 간에 동작이 보장되는 구조라는 점에서 본질적인 차이가 있다.

 

 

Handshake CDC의 기본 구조: Request / Acknowledge

 

Handshake CDC는 기본적으로 Request(req) / Acknowledge(ack) 두 개의 싱글 비트 제어 신호를 이용해 동작한다.

  • req (request)
    송신 도메인(Source Clock Domain)에서 "멀티비트 데이터가 준비되었고 현재 안정 상태임"을 알리는 신호
  • ack (acknowledge)
    수신 도메인(Destination Clock Domain)에서 "데이터를 정상적으로 샘플링했음"을 알리는 신호

이 두 신호만이 2-FF Synchronizer를 통해 서로의 클럭 도메인으로 전달되며, 멀티비트 데이터 버스 자체는 CDC 대상이 아니다.

 

 

Handshake CDC 동작 시퀀스

Handshake CDC의 동작은 다음과 같은 순서로 진행된다.

 

1. Source Domain: Request 발생

송신 도메인은 전송할 멀티비트 데이터를 내부 레지스터에 저장한 뒤, req 신호를 1로 설정한다.

  • req = 1 인 동안 데이터는 절대 변경되지 않는다
  • 이 구간이 바로 수신 도메인이 데이터를 안전하게 샘플링할 수 있는 stable window가 된다

2. Request 신호의 CDC

req 신호는 싱글 비트 제어 신호이므로 2-FF Synchronizer를 통해 수신 도메인으로 전달된다.

  • req의 도착 시점은 클럭 비율에 따라 달라질 수 있음
  • 하지만 level 신호이므로 도착 지연 자체는 기능적 문제가 되지 않음

3. Destination Domain: 데이터 샘플링 및 Acknowledge 발생

수신 도메인은 동기화된 req 신호를 감지하면, 해당 클럭 엣지에서 멀티비트 데이터 버스를 샘플링한다.

  • 이 시점에서 데이터는 Source Domain에서 고정된 상태
  • bit 간 skew 없이 하나의 일관된 값으로 샘플링됨

샘플링이 완료되면 ack 신호를 1로 설정하여 데이터 수신 완료를 알린다.

 

4. Acknowledge 신호의 역방향 CDC

ack 신호 역시 2-FF Synchronizer를 통해 송신 도메인으로 전달된다.

송신 도메인은 ack를 감지한 후 req를 0으로 내리고, 다음 데이터 전송을 준비한다.

 

 

Handshake CDC와 Stretching 방식의 차이

Stretching 방식은 송신 도메인에서 pulse를 충분히 늘려 수신 도메인에서 감지하도록 하는 방식이다. 그러나 이 방식은 다음과 같은 한계를 가진다.

  • 두 클럭의 주파수 비율을 정확히 가정해야 함
  • 클럭 비율이 변경되면 재설계 필요
  • worst-case를 가정한 과도한 stretch 필요

반면 Handshake CDC는 ack를 기반으로 동작 완료를 명확히 확인하기 때문에 클럭 속도 비율과 무관하게 항상 안전한 동작을 보장한다.

 

 

Code

module handshake_cdc #(
    parameter DATA_W = 8
)(
    // Source domain
    input  logic             clk_src,
    input  logic             rst_src_n,
    input  logic             valid_src,   // <-- VALID
    input  logic [DATA_W-1:0] data_in,

    // Destination domain
    input  logic             clk_dst,
    input  logic             rst_dst_n,

    output logic [DATA_W-1:0] data_out,
    output logic             valid_dst    // one transfer indication
);

    // =================================
    // Source domain
    // =================================
    logic [DATA_W-1:0] data_bus;
    logic req;

    // =================================
    // Destination domain
    // =================================
    logic ack;

    // =================================
    // CDC synchronizers
    // =================================
    logic req_ff1, req_sync;
    logic ack_ff1, ack_sync;

    // -------------------------------------------------
    // Source domain logic
    // -------------------------------------------------
    always_ff @(posedge clk_src or negedge rst_src_n) begin
        if (!rst_src_n) begin
            req      <= 1'b0;
            data_bus <= '0;
        end else begin
            if (!req && valid_src) begin
                data_bus <= data_in; // 데이터 고정
                req      <= 1'b1;    // request 발생
            end
            else if (req && ack_sync) begin
                req <= 1'b0;         // handshake 완료
            end
        end
    end

    // -------------------------------------------------
    // REQ synchronizer (SRC -> DST)
    // -------------------------------------------------
    always_ff @(posedge clk_dst or negedge rst_dst_n) begin
        if (!rst_dst_n) begin
            req_ff1  <= 1'b0;
            req_sync <= 1'b0;
        end else begin
            req_ff1  <= req;
            req_sync <= req_ff1;
        end
    end

    // -------------------------------------------------
    // Destination domain logic
    // -------------------------------------------------
    always_ff @(posedge clk_dst or negedge rst_dst_n) begin
        if (!rst_dst_n) begin
            ack       <= 1'b0;
            data_out  <= '0;
            valid_dst <= 1'b0;
        end else begin
            if (req_sync && !ack) begin
                data_out  <= data_bus; // stable window sampling
                valid_dst <= 1'b1;
                ack       <= 1'b1;
            end
            else if (!req_sync) begin
                ack       <= 1'b0;
                valid_dst <= 1'b0;
            end
        end
    end

    // -------------------------------------------------
    // ACK synchronizer (DST -> SRC)
    // -------------------------------------------------
    always_ff @(posedge clk_src or negedge rst_src_n) begin
        if (!rst_src_n) begin
            ack_ff1  <= 1'b0;
            ack_sync <= 1'b0;
        end else begin
            ack_ff1  <= ack;
            ack_sync <= ack_ff1;
        end
    end

endmodule


module tb_handshake_cdc;

    localparam DATA_W = 8;

    logic clk_src = 0;
    logic clk_dst = 0;
    logic rst_n   = 0;

    always #5  clk_src = ~clk_src;   // 100 MHz
    always #11 clk_dst = ~clk_dst;   // ~45 MHz (비동기)

    logic valid_src;
    logic [DATA_W-1:0] data_in;
    logic [DATA_W-1:0] data_out;
    logic valid_dst;

    handshake_cdc #(.DATA_W(DATA_W)) dut (
        .clk_src   (clk_src),
        .rst_src_n (rst_n),
        .valid_src (valid_src),
        .data_in   (data_in),
        .clk_dst   (clk_dst),
        .rst_dst_n (rst_n),
        .data_out  (data_out),
        .valid_dst (valid_dst)
    );

    initial begin
        valid_src = 0;
        data_in   = 0;
        rst_n     = 0;

        #40;
        rst_n = 1;

        // Transfer #1
        #30;
        data_in   = 8'hA5;
        valid_src = 1;
        #10;
        valid_src = 0;

        // Transfer #2
        #200;
        data_in   = 8'h3C;
        valid_src = 1;
        #10;
        valid_src = 0;

        // Transfer #3
        #200;
        data_in   = 8'hF0;
        valid_src = 1;
        #10;
        valid_src = 0;

        #400;
        $finish;
    end
  
    // Waveform dump
    initial begin
      $dumpfile("handshake_cdc.vcd");
      $dumpvars(0, tb_handshake_cdc);
    end


endmodule

 

Simulation

 

Source Domain (송신 도메인)

  • valid_src가 assert되면 입력 데이터를 내부 data_bus에 래치
  • req를 assert하여 전송 요청 발생
  • ack가 동기화되어 돌아오면 (ack_sync)
    • handshake 완료로 판단
    • req deassert
  • req가 deassert될 때까지 데이터는 고정됨

Destination Domain (수신 도메인)

  • 동기화된 req_sync를 감지
  • req_sync가 assert되면
    • 데이터 버스를 샘플링
    • valid_dst를 통해 데이터 수신을 알림
    • ack assert
  • req_sync가 deassert되면
    • ack 및 valid_dst deassert

 

본 설계는 단일 outstanding transaction만 허용한다.

  • req == 1인 동안은 새로운 데이터 전송이 불가능
  • valid_src는 반드시 req == 0 상태에서만 assert되어야 함
  • handshake 완료 이전에 들어온 데이터는 무시됨

이 구조가 의도하지 않은 것

  • 연속 데이터 스트리밍
  • multiple outstanding transaction

이러한 기능은 FIFO 결합 또는 VALID/READY 구조를 통해 확장되어야 한다.

728x90
반응형
저작자표시 비영리 변경금지 (새창열림)

'VLSI > Design' 카테고리의 다른 글

[CDC] 6_Multi Bit CDC: Asynchronous FIFO (Introduction)  (0) 2025.12.19
[CDC] 5_Multi Bit CDC: Gray Code  (0) 2025.12.15
[CDC] 3_Single Bit CDC: Simulation Result  (0) 2025.12.07
[CDC] 2_Single Bit CDC: Toggle Synchronizer  (0) 2025.12.07
[CDC] 1_Single Bit CDC: 2-FF Synchronizer  (0) 2025.12.07
'VLSI/Design' 카테고리의 다른 글
  • [CDC] 6_Multi Bit CDC: Asynchronous FIFO (Introduction)
  • [CDC] 5_Multi Bit CDC: Gray Code
  • [CDC] 3_Single Bit CDC: Simulation Result
  • [CDC] 2_Single Bit CDC: Toggle Synchronizer
리미와감자
리미와감자
공부한 내용을 포스팅합니다.
    반응형
    250x250
  • 리미와감자
    리미창고
    리미와감자
  • 전체
    오늘
    어제
    • 분류 전체보기 (213)
      • Programming (92)
        • Common (6)
        • C (3)
        • C++ (16)
        • Python (35)
        • Front End (8)
        • Linux (1)
        • Script (7)
        • Data Structure (5)
        • Tool (11)
      • Computer Science (0)
      • VLSI (30)
        • Common (4)
        • Design (15)
        • SystemVerilog (9)
        • UVM (2)
        • FPGA (0)
      • Embedded System (31)
        • Arduino (2)
        • STM32 (7)
        • Embedded Recipes (22)
      • Semiconductor (11)
        • Semiconductor Device (1)
        • Display (10)
      • Algorithm (8)
        • Image Processing (8)
        • AI (0)
      • Certificate (26)
        • ADsP (26)
      • 일상생활 (15)
        • 맛집 리뷰 (4)
        • 나는 오늘 무엇을 샀나 ! (5)
        • 국내여행 (5)
        • 나들이 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 최근 글

  • 최근 댓글

  • 태그

    SVA
    Clock Domain Crossing
    Handshake
    디더링
    Bash
    오블완
    임베디드레시피
    파이참
    git
    Dither
    systemverilog assertions
    군산가볼만한곳
    arduino
    티스토리챌린지
    Metastability
    자료구조
    assertion
    Asynchronous FIFO
    SystemVerilog
    c++ 기초
    openpyxl
    data structure
    UVM
    tkinter
    임베디드시스템
    STM32
    CDC
    아두이노
    BeautifulSoup4
    ADsP
  • 링크

    • chipverify
    • vlsiverify
    • iksciting
    • 오늘은 맑음
    • verificationguide
  • hELLO· Designed By정상우.v4.10.6
리미와감자
[CDC] 4_Multi Bit CDC: Handshake
상단으로

티스토리툴바