SystemVerilog 기반 Glitch-free Clock Divider 설계 가이드
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
⚡ Glitch-free Clock Divider 설계 완전 가이드 — FPGA/ASIC 클락 분주기의 핵심
디지털 회로 설계 | SystemVerilog | FPGA 클럭 관리 | RTL 설계 기법
FPGA나 ASIC 설계에서 클락 분주기(Clock Divider)는 거의 모든 프로젝트에 빠짐없이 등장하는 핵심 컴포넌트입니다. 하지만 단순히 카운터로 클락을 나누면 글리치(Glitch)라는 치명적인 노이즈가 발생하여 시스템 전체의 타이밍 안정성을 무너뜨릴 수 있습니다. 이 글에서는 Glitch-free Clock Divider의 설계 원리부터 실무 적용까지, 실제 합성 가능한 SystemVerilog 코드와 함께 깊이 있게 다룹니다.
📌 이 글의 핵심: 글리치가 왜 위험한지, 이를 방지하는 3가지 설계 기법, 그리고 짝수/홀수 분주를 모두 지원하는 50% Duty Cycle 분주기 RTL 코드를 제공합니다.
🔧 1. 클락 분주기 — 기본 원리부터 짚고 가자
▶ 카운터 기반 분주의 기본 동작
가장 직관적인 분주 방식은 카운터를 사용하는 것입니다. 예를 들어 4분주를 구현하고 싶다면, 소스 클락이 2번 뛸 때마다 출력 상태를 반전시키면 됩니다. 구현이 간단하고 이해하기 쉽다는 장점이 있지만, 이 과정에서 조합 논리(Combinational Logic)의 게이트별 전파 지연 시간(Propagation Delay) 차이로 인해 아주 짧은 시간 동안 잘못된 값이 출력되는 글리치가 발생할 수 있습니다.
⚠️ 글리치(Glitch)란? 조합 회로에서 입력이 동시에 변할 때, 각 경로의 지연 차이로 인해 최종 출력이 안정되기 전에 순간적으로 잘못된 값이 나타나는 현상입니다. 이것이 클락 라인에 발생하면 하위 회로가 '가짜 클락 에지'로 인식하여 심각한 오동작을 일으킵니다.
▶ 심화: Clock Skew와 Duty Cycle 이해
🕐 Clock Skew — 클락 신호가 서로 다른 플립플롭에 도달하는 시간 차이입니다. 분주된 클락이 비동기적으로 동작할 경우, Skew로 인해 Setup/Hold 타이밍 위반이 발생하며 데이터 샘플링 오류로 이어집니다.
📊 Duty Cycle — 클락의 High 구간과 전체 주기의 비율입니다. 짝수 분주(2, 4, 6분주 등)에서 50% Duty Cycle은 자연스럽게 달성되지만, 홀수 분주(3, 5, 7분주 등)에서 정확한 50%를 맞추려면 정교한 설계 기법이 필요합니다.
💥 글리치의 파급력 — 데이터 경로의 글리치는 다음 클락 에지에서 올바른 값으로 덮어씌워지므로 비교적 안전합니다. 하지만 클락 경로의 글리치는 해당 클락을 사용하는 모든 플립플롭을 잘못 트리거하여, 시스템 전체를 불안정한 상태로 몰아갈 수 있습니다.
🛡️ 2. 글리치 방지를 위한 3가지 핵심 설계 기법
글리치를 방지하기 위해 실무에서 가장 널리 쓰이는 기법들을 정리합니다.
① Registering Outputs (출력 레지스터링)
조합 논리로 생성된 분주 신호를 반드시 플립플롭(Flip-Flop)을 통과시켜 출력합니다. 플립플롭은 클락의 에지에서만 값이 변경되므로, 에지 사이에 발생하는 중간 과도 상태(글리치)를 완벽하게 차단합니다. 이것이 Glitch-free 설계의 가장 기본이자 핵심 원칙입니다.
② Posedge & Negedge Mixing (듀얼 에지 결합)
홀수 분주에서 50% Duty Cycle을 달성하기 위한 기법입니다. 상승 에지(Posedge)에서 동작하는 신호와 하강 에지(Negedge)에서 동작하는 신호를 각각 생성한 뒤, 이 두 신호를 OR 또는 AND 연산으로 결합합니다. 하강 에지 신호가 반주기 쉬프트 역할을 하여 자연스럽게 50% Duty를 만들어냅니다.
③ Grey Code Counter (그레이 코드 카운터)
일반 바이너리 카운터는 상태 전이 시 여러 비트가 동시에 변하며, 이 과정에서 과도기적 글리치가 발생합니다. 그레이 코드는 인접 상태 간 비트 1개만 변화하므로, 멀티비트 전이에서 생기는 글리치를 원천적으로 줄일 수 있습니다. 특히 CDC(Clock Domain Crossing) 설계에서도 많이 활용됩니다.
💻 3. SystemVerilog 구현 — Glitch-free Divider 전체 코드
아래 코드는 짝수/홀수 분주를 모두 지원하며, 50% Duty Cycle을 유지하는 합성 가능한(Synthesizable) Glitch-free 분주기입니다.
// 📁 glitch_free_divider.sv
module glitch_free_divider #(
parameter DIVIDE_BY = 3 // 분주비 설정 (예: 3분주)
)(
input logic clk, // 소스 클락
input logic rst_n, // 비동기 리셋 (Active Low)
output logic clk_out // 분주된 결과 클락
);
// 내부 카운터
logic [$clog2(DIVIDE_BY)-1:0] count;
// 듀얼 에지 중간 신호
logic pos_clk; // 상승 에지용
logic neg_clk; // 하강 에지용
// ─── 1. 메인 카운터 ───
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n)
count <= '0;
else if (count == DIVIDE_BY - 1)
count <= '0;
else
count <= count + 1;
end
// ─── 2. Posedge 신호 (레지스터링) ───
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n)
pos_clk <= 1'b0;
else if (count < (DIVIDE_BY >> 1) + (DIVIDE_BY % 2))
pos_clk <= 1'b1;
else
pos_clk <= 1'b0;
end
// ─── 3. Negedge 신호 (반주기 쉬프트) ───
always_ff @(negedge clk or negedge rst_n) begin
if (!rst_n)
neg_clk <= 1'b0;
else
neg_clk <= pos_clk;
end
// ─── 4. 최종 출력 결합 ───
assign clk_out = (DIVIDE_BY % 2 == 0) ? pos_clk : (pos_clk | neg_clk);
endmodule
🔍 4. 코드 동작 원리 상세 분석
▶ always_ff — 글리치 차단의 핵심
모든 상태 변화가 always_ff 블록 안에서 일어납니다. pos_clk와 neg_clk는 클락 에지에 동기화된 레지스터 출력이므로, 에지 사이에 발생하는 조합 논리의 과도 상태가 출력에 전파되지 않습니다. 이것이 바로 "Registering으로 글리치를 차단한다"는 원리의 구현입니다.
▶ 홀수 분주 원리 (DIVIDE_BY = 3)
3분주를 예로 들어 동작 과정을 단계별로 살펴보겠습니다.
pos_clk는 상승 에지에서 동작하며, count 값에 따라 2주기 High → 1주기 Low를 반복합니다 (Duty ≈ 66%).
neg_clk는 하강 에지에서 pos_clk를 샘플링하므로, pos_clk 대비 정확히 반주기 지연된 파형이 됩니다.
두 신호를 OR 연산하면, High 구간이 1.5주기로 확장되어 전체 3주기 중 정확히 절반 → 50% Duty Cycle 달성!
📐 3분주 타이밍 다이어그램
| clk |
|
| count |
0
1
2
0
1
2
|
| pos_clk |
|
| neg_clk |
|
| clk_out |
|
pos_clk neg_clk clk_out (OR)
▶ 합성 가능성 (Synthesizability)
이 코드는 특수한 프리미티브(Primitive)를 사용하지 않고 표준 SystemVerilog 문법만으로 작성되었습니다. AMD Vivado, Intel Quartus, Synopsys Design Compiler 등 주요 합성 툴에서 안정적으로 합성되며, FPGA와 ASIC 플로우 모두에 적용 가능합니다.
🏭 5. 실무 적용 팁과 주의사항
🔌 Clock Buffer 사용 필수 — 분주기 출력을 직접 로직의 클락 포트에 연결하면 안 됩니다. FPGA에서는 BUFG(Global Clock Buffer)를 통해 클락 트리에 올려야 Skew를 최소화할 수 있습니다. Vivado에서는 BUFGCE를 사용하면 클락 인에이블 기능도 함께 구현할 수 있어 편리합니다.
⚙️ 고주파 설계 시 추가 레지스터링 — 수백 MHz 이상의 고주파 환경에서는 assign 문의 조합 논리 지연도 문제가 될 수 있습니다. 최종 출력단에 레지스터를 한 단계 더 추가하거나, MMCM(Mixed-Mode Clock Manager)이나 PLL(Phase-Locked Loop) 같은 전용 Clock Management IP를 사용하는 것이 바람직합니다.
🔄 CDC(Clock Domain Crossing) 고려 — 분주된 클락으로 동작하는 회로와 원래 클락으로 동작하는 회로 사이에 데이터를 교환할 때는 반드시 동기화기(Synchronizer)를 삽입해야 합니다. 최소 2-stage 플립플롭 동기화기를 사용하고, 고신뢰성이 요구되면 3-stage를 권장합니다.
🧪 시뮬레이션 검증 포인트 — 분주기를 설계한 후에는 반드시 다음 항목을 확인하세요: ① 리셋 직후 출력이 깔끔한 Low인지, ② Duty Cycle이 정확히 50%인지, ③ 분주비가 parameter 변경에 따라 올바르게 동작하는지, ④ 글리치가 없는지 파형을 확대하여 면밀히 점검합니다.
🆚 6. 분주 방식 비교 — 어떤 기법을 선택할까?
| 방식 | 글리치 안전성 | 50% Duty | 리소스 사용량 | 적합 용도 |
|---|---|---|---|---|
| 단순 카운터 | ❌ 위험 | 짝수만 가능 | 최소 | 학습/프로토타입 |
| 레지스터링 분주 | ✅ 안전 | 짝수만 가능 | 낮음 | 짝수 분주 프로덕션 |
| 듀얼 에지 결합 (본 코드) | ✅ 안전 | ✅ 짝수+홀수 | 중간 | 범용 프로덕션 |
| MMCM / PLL | ✅ 최상 | ✅ 짝수+홀수 | 전용 하드웨어 | 고주파/정밀 요구 |
📋 7. 흔히 하는 실수와 체크리스트
❌ 실수 1: assign으로 바로 분주 신호 생성 → 조합 논리 글리치가 클락 라인에 직접 전파됩니다. 반드시 플립플롭을 거쳐야 합니다.
❌ 실수 2: 분주 클락을 BUFG 없이 사용 → FPGA 내부에서 심각한 Clock Skew가 발생하며, Place & Route에서 타이밍 위반이 보고됩니다.
❌ 실수 3: CDC 동기화 누락 → 서로 다른 클락 도메인 간 데이터 전달 시 메타스테이빌리티(Metastability)가 발생하여 간헐적 오류가 생깁니다.
❌ 실수 4: 리셋 신호 미처리 → 파워온 시 카운터가 불확정(X) 상태에서 시작하면 분주기 전체가 예측 불가능한 상태가 됩니다.
✅ 설계 전 체크리스트
→ 모든 분주 신호가 플립플롭을 통과하는가?
→ 비동기 리셋이 적절히 처리되었는가?
→ 출력 클락이 BUFG/Clock Buffer를 거치는가?
→ CDC 경계에 동기화기가 삽입되었는가?
→ 시뮬레이션에서 Duty Cycle과 글리치를 확인했는가?
🎯 마무리
Glitch-free Clock Divider는 단순히 "클락을 나누는" 것을 넘어, 시스템 전체의 타이밍 안정성을 보장하는 핵심 설계 기법입니다. 핵심은 세 가지로 요약됩니다: ① 모든 분주 신호는 반드시 레지스터링할 것, ② 홀수 분주에서 50% Duty가 필요하면 듀얼 에지 결합을 사용할 것, ③ 출력은 반드시 Clock Buffer를 통해 배포할 것. 이 원칙을 지키면 어떤 분주비에서도 안정적인 클락을 생성할 수 있습니다.
📚 참고 자료
→ AMD/Xilinx 7 Series FPGA Clocking Resources (UG472)
→ Intel FPGA RTL Design Guidelines
→ Synopsys Design Compiler User Guide — Clock Gating
본 콘텐츠는 정보 제공 목적으로 작성되었으며, 실제 설계 시에는 사용하시는 FPGA/ASIC 벤더의 공식 문서와 Design Rule을 반드시 확인하시기 바랍니다.
📄 Raw Data
디지털 회로 설계, 특히 FPGA나 ASIC 설계에서 클락 분주기(Clock Divider)는 필수적인 요소입니다. 하지만 단순히 카운터를 이용해 클락을 나누게 되면 **글리치(Glitch)**라는 불필요한 노이즈가 발생하여 시스템 전체의 타이밍 안정성을 해칠 수 있습니다. 오늘은 안정적인 시스템 운영을 위한 **Glitch-free Clock Divider** 설계 기법에 대해 심도 있게 알아보겠습니다.
---
### 1. 클락 분주기를 위한 기본 및 심화 지식
#### 기본 지식: 카운터 기반 분주
가장 기본적인 분주 방식은 카운터를 사용하는 것입니다. 예를 들어, 4분주를 하고 싶다면 클락이 2번 뛸 때마다 출력 상태를 반전시키는 방식입니다. 하지만 이 과정에서 조합 논리(Combinational Logic)의 지연 시간 차이로 인해 아주 짧은 시간 동안 잘못된 값이 출력되는 **글리치**가 발생할 수 있습니다.
#### 심화 지식: 클락 도메인과 타이밍 분석
* **Clock Skew:** 클락 신호가 서로 다른 플립플롭에 도달하는 시간 차이입니다. 분주된 클락이 비동기적으로 동작할 경우 Skew로 인해 데이터 샘플링 오류가 발생합니다.
* **Duty Cycle:** 클락의 'High' 구간과 전체 주기 사이의 비율입니다. 짝수 분주는 쉽지만, 홀수 분주(3분주, 5분주 등)에서 50%의 Duty Cycle을 맞추는 것은 정교한 설계가 필요합니다.
* **Glitch의 위험성:** 클락 라인에 발생한 글리치는 이를 클락으로 사용하는 하위 회로에서 '가짜 클락'으로 인식되어 원치 않는 동작을 유발합니다.
---
### 2. 설계 단에서의 글리치 방지 기법
글리치를 방지하기 위해 가장 널리 쓰이는 기법은 **순차 논리(Sequential Logic) 기반의 리타이밍**과 **Clock Gating Cell** 활용입니다.
1. **Registering Outputs:** 조합 논리로 만들어진 분주 신호를 반드시 플립플롭(Flip-Flop)을 통과시켜 출력합니다. 플립플롭은 클락의 에지에서만 값이 변하므로 중간 과정의 글리치를 차단합니다.
2. **Negedge & Posedge Mixing:** 홀수 분주의 경우, 상승 에지와 하강 에지에서 동작하는 두 개의 신호를 생성한 뒤 이를 논리합(OR) 또는 논리곱(AND) 연산하여 글리치 없는 파형을 만듭니다.
3. **Grey Code Counter:** 상태 변화 시 비트가 하나만 변하는 그레이 코드를 사용하면 여러 비트가 동시에 변할 때 생기는 과도기적 글리치를 줄일 수 있습니다.
---
### 3. SystemVerilog Glitch-free Divider 예시 코드
아래 코드는 가장 범용적인 **짝수/홀수 분주가 모두 가능하며 50% Duty Cycle을 유지하는 Glitch-free 분주기**입니다.
```systemverilog
module glitch_free_divider #(
parameter DIVIDE_BY = 3 // 분주비 설정 (예: 3분주)
)(
input logic clk, // 소스 클락
input logic rst_n, // 비동기 리셋
output logic clk_out // 분주된 결과 클락
);
// 내부 카운터 정의
logic [$clog2(DIVIDE_BY)-1:0] count;
// 상승 에지(Posedge)에서 동작하는 중간 신호
logic pos_clk;
// 하강 에지(Negedge)에서 동작하는 중간 신호
logic neg_clk;
// 1. 메인 카운터 로직
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
count <= '0;
end else begin
if (count == DIVIDE_BY - 1)
count <= '0;
else
count <= count + 1;
end
end
// 2. Posedge 신호 생성 (Glitch 방지를 위해 Registering)
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
pos_clk <= 1'b0;
end else begin
// 분주비의 절반 지점에서 신호 반전
if (count < (DIVIDE_BY >> 1) + (DIVIDE_BY % 2))
pos_clk <= 1'b1;
else
pos_clk <= 1'b0;
end
end
// 3. Negedge 신호 생성 (홀수 분주 시 50% Duty Cycle을 위함)
// pos_clk를 반주기 쉬프트 시키는 효과
always_ff @(negedge clk or negedge rst_n) begin
if (!rst_n) begin
neg_clk <= 1'b0;
end else begin
neg_clk <= pos_clk;
end
end
// 4. 최종 출력 결합
// 홀수 분주일 때는 두 신호를 OR 연산하여 50% Duty를 맞추고 글리치를 억제함
assign clk_out = (DIVIDE_BY % 2 == 0) ? pos_clk : (pos_clk | neg_clk);
endmodule
```
---
### 4. 코드 상세 설명 및 원리 이해
* **`always_ff`의 사용:** 모든 상태 변화는 플립플롭 내부에서 일어납니다. `pos_clk`와 `neg_clk`는 클락 에지에 동기화되어 있으므로, 출력단(`assign`)에 도달하기 전까지의 모든 조합 논리 글리치는 플립플롭에 의해 걸러집니다.
* **홀수 분주 원리 (DIVIDE_BY = 3 일 때):**
* `pos_clk`는 소스 클락의 상승 에지에서 2주기 동안 High, 1주기 동안 Low가 됩니다.
* `neg_clk`는 `pos_clk`를 하강 에지에서 샘플링하므로 반주기 뒤쳐진 신호가 됩니다.
* 두 신호를 `OR` 연산하면 High 구간이 1.5주기가 되어, 결과적으로 전체 3주기 중 절반을 High로 채우는 깔끔한 50% Duty Cycle 클락이 완성됩니다.
* **합성 가능성(Synthesizable):** 이 코드는 특수한 프리미티브(Primitive)를 사용하지 않고 표준 SystemVerilog 문법만 사용했으므로, Vivado, Quartus, Design Compiler 등 대부분의 툴에서 안정적으로 합성됩니다.
### 5. 실무 적용 팁 및 주의사항
실제 프로젝트에서는 클락 분주기 출력을 직접 로직의 클락 포트에 연결하는 **Clock Buffer** 처리가 중요합니다. FPGA 설계 시에는 `BUFG`와 같은 전역 클락 버퍼를 사용하여 Skew를 최소화해야 합니다. 또한, 아주 높은 주파수에서는 `assign` 문에서의 지연조차 문제가 될 수 있으므로, 최종 단계에서 한번 더 Registering을 수행하거나 전용 **Clock Management IP(MMCM/PLL)** 사용을 권장합니다.
---
## References
- [FPGA Clocking Resources](https://docs.amd.com/r/en-US/ug472_7Series_Clocking)
- [RTL Design Guidelines](https://www.intel.com/content/www/us/en/docs/programmable/683082/22-4/rtl-design-guidelines.html)
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
댓글
댓글 쓰기