1. 소개
Verilog에서 always 블록의 역할은 무엇인가요?
Verilog HDL은 디지털 회로 설계에 널리 사용되는 하드웨어 기술 언어이며, always 블록은 중요한 역할을 합니다. 소프트웨어처럼 하드웨어 동작을 기술하는 것이 아니라, Verilog은 “신호가하는가” 를 정의함으로써 회로를 표현합니다. 이 중 always 블록은 특정 조건이 발생했을 때 어떤 동작을 수행해야 하는지 를 기술하는 기본적인 구조입니다.왜 always 블록이 필요할까요?
Verilog에서는 설명할 수 있는 회로 동작이 두 가지 주요 유형으로 나뉩니다.- 조합 논리 : 입력이 변하면 출력이 즉시 변함
- 순차 논리 : 클록 신호나 타이밍 이벤트와 동기화되어 출력이 변함
단순 assign 문만으로는 복잡한 조건이나 메모리 요소를 다룰 수 없습니다. 여기서 always 블록이 등장합니다. 예를 들어 조건 분기나 플립플롭 동작을 기술하려면 if 혹은 case와 같은 제어 구조를 포함한 always 블록이 필요합니다.always 블록의 일반적인 패턴
설계하려는 회로 유형에 따라 always 블록은 여러 가지 일반적인 사용 패턴을 가집니다.always @(*) → 조합 논리용always @(posedge clk) → 클록 상승 에지에서 트리거되는 순차 논리always @(posedge clk or negedge rst) → 비동기 리셋 또는 더 복잡한 제어가 포함된 순차 논리
따라서 Verilog의 핵심 구문인 always 블록을 이해하는 것은 하드웨어 설계자에게 필수적인 첫 단계입니다.이 글의 목적
이 글에서는 Verilog의 always 블록에 대해 기본 구문, 실용적인 사용법, 흔히 발생하는 함정, SystemVerilog 확장 등을 포괄적으로 다룹니다.- 올바른
always 블록 작성 방법 학습 - 합성 오류가 발생하는 이유 이해
=와 <=의 차이점 명확히 파악- 초보자들이 흔히 저지르는 실수 방지
이 가이드를 통해 관련 질문을 가진 누구나 실용적이고 이해하기 쉬운 정보를 얻을 수 있기를 바랍니다.
2. always 블록의 기본 구문 및 유형
always 블록의 기본 구문
Verilog에서 always 블록은 특정 민감도 리스트에 따라 문장을 반복 실행합니다. 기본 구문은 다음과 같습니다.always @(sensitivity list)
begin
// statements
end
여기서 핵심은 “민감도 리스트” 로, 어떤 신호가 변할 때 블록이 실행될지를 정의합니다.조합 논리를 위한 always @(*) 사용
조합 논리에서는 입력이 변할 때마다 출력이 즉시 업데이트되어야 합니다. 이 경우 민감도 리스트로 @(*) 를 사용합니다.always @(*) begin
if (a == 1'b1)
y = b;
else
y = c;
end
즉, a, b, c 중 하나라도 변하면 always 블록이 실행되어 y 를 다시 계산합니다.@(*) 사용의 장점
- 참조된 모든 신호를 자동으로 민감도 리스트에 포함
- 시뮬레이션 결과와 합성 결과 간의 불일치 방지
순차 논리를 위한 always @(posedge clk) 사용
순차 논리에서는 상태 변화가 클록 신호와 동기화됩니다. 이 경우 민감도 리스트에 posedge clk 를 명시합니다.always @(posedge clk) begin
q <= d;
end
여기서는 클록 상승 에지에서 d 의 값이 q 로 래치됩니다. 연산자 <= 는 비블로킹 할당을 의미하며, 순차 논리에서 표준으로 사용됩니다.posedge 와 negedge 비교
posedge : 상승 에지에서 트리거negedge : 하강 에지에서 트리거
설계 요구에 따라 적절한 에지를 선택하십시오.비동기 리셋을 포함한 always @(posedge clk or negedge rst)
복잡한 회로에서는 리셋 기능이 자주 필요합니다. 비동기 리셋을 포함한 블록은 다음과 같이 작성할 수 있습니다.always @(posedge clk or negedge rst) begin
if (!rst)
q <= 1'b0;
else
q <= d;
end
위와 기술하면 rst 가 낮을 때 q 가 즉시 리셋되고, 그렇지 않을 경우 클록 에지에서 d 를 캡처합니다.조합 논리 vs 순차 논리
| 회로 유형 | always | 행동 |
|---|
| 조합 | always @(*) | 입력에 따라 출력이 즉시 업데이트됩니다 |
| 순차적 | always @(posedge clk) | 시계와 동기화되어 작동합니다 |
3. always 블록에서의 할당 유형
Verilog의 두 가지 할당 연산자
Verilog always 블록 안에서는 두 가지 다른 할당 연산자를 사용할 수 있습니다: 이 차이를 오해하면 예상치 못한 동작과 시뮬레이션과 합성 간의 불일치가 발생할 수 있어, 가장 중요한 포인트 중 하나입니다.블로킹 할당 (=)
블로킹 할당은 순차적으로, 한 문장씩 차례대로 실행됩니다. 이는 소프트웨어 제어 흐름과 유사합니다.always @(*) begin
a = b;
c = a;
end
여기서 a = b가 먼저 실행되고, 그 다음에 c = a가 업데이트된 a 값을 사용합니다. 문장의 순서가 논리 동작에 직접적인 영향을 미칩니다.전형적인 사용 사례
- 조합 논리에서의 제어 구조(
if, case) - 상태를 유지할 필요가 없는 논리
논블로킹 할당 (<=)
논블로킹 할당은 모든 문장이 동시에 평가되고 한 번에 업데이트된다는 의미이며, 하드웨어의 병렬성을 표현합니다.always @(posedge clk) begin
a <= b;
c <= a;
end
a <= b와 c <= a가 동시에 평가되고 클록 엣지 이후에 업데이트됩니다. 따라서 c는 이전 a 값을 받게 됩니다.전형적인 사용 사례
- 순차 논리(레지스터, 플립플롭)
- 여러 신호에 걸친 정확한 상태 전파
블로킹 vs 논블로킹 할당: 비교
| 기능 | 차단 (=) | 논블로킹 (<=) |
|---|
| 실행 순서 | 순차적으로, 하나씩 차례대로 | 동시에 평가되고, 함께 업데이트됩니다 |
| 일반적인 사용법 | 조합 논리 | 순차 논리 |
| 업데이트 타이밍 | 즉시 적용 | 클럭 엣지 이후에 적용됨 |
| 일반적인정 | 예기치 않은 래치 생성 | 값이 예상대로 업데이트되거나 전파되지 않음 |
둘을 섞어 쓰면 어떻게 될까?
같은 블록이나 같은 신호에서 =와 <=를 섞어 사용하면 안 됩니다. 예를 들어:always @(posedge clk) begin
a = b;
a <= c;
end
이 코드는 a에 두 번 다른 방법으로 할당하여 최종 저장값이 모호해집니다. 시뮬레이션에서는 정상적으로 보일 수 있지만 하드웨어에서는 실패할 수 있습니다.사용 가이드라인
always @(*) 블록 안 = 사용 (조합 논리)always @(posedge clk) 블록 안에서는 <= 사용 (순차 논리)
이 간단한 규칙을 따르면 흔히 발생하는 실수를 많이 방지할 수 있습니다. 
4. always 블록의 흔한 함정과 모범 사례
민감도 리스트에서의 실수
잘못된 민감도 리스트는 숨은 버그를 유발
Verilog에서 민감도 리스트(@(...))는 실행을 트리거하는 모든 신호를 명시적으로 포함해야 합니다. 다음은 일부 신호만 포함된 예시입니다:always @(a) begin
if (b)
y = 1'b1;
else
y = 1'b0;
end
이 코드는 b의 변화에 반응하지 않습니다. 결과적으로 b가 변해도 y가 업데이트되지 않아 버그가 발생합니다.해결책: @(*) 사용
민감도 리스트에서 신호를 놓치지 않으려면 다음과 같이 @(*)를 사용합니다:always @(*) begin
if (b)
y = 1'b1;
else
y = 1'b0;
end
@(*)는 블록 안에서 참조된 모든 신호를 자동으로 포함하므로 유지보수성과 신뢰성이 향상됩니다.의도치 않은 래치 생성
if/case 분기가 누락되면 래치가 생성
모든 경우에 값을 할당하지 않으면 합성 도구는 변수가 값을 “보유”해야 한다고 판단해 래치를 생성합니다:always @(*) begin
if (enable)
y = d; // y is undefined when enable == 0
end
보기에 문제 없어 보이지만, enable이 0일 때 y가 업데이트되지 않으므로 래치가 삽입됩니다.해결책: 항상 값을 할당
always @(*) begin
if (enable)
y = d;
else
y = 1'b0; // y is always defined
end
모든 경우에 값을 명시적으로 할당함으로써 원치 않는 래치를 방지할 수 있습니다.과도하게 복잡한 조건문
복잡한 if 또는 case 문은 조건이 모두 커버되지 않을 경우 정의되지 않은 동작이나 로직 누락을 초래할 수 있습니다.전형적인 실수: case 문에 default가 없음
always @(*) begin
case(sel)
2'b00: y = a;
2'b01: y = b;
2'b10: y = c;
// 2'b11 not handled → y may be undefined
endcase
end
해결책: default 절 추가
always @(*) begin
case(sel)
2'b00: y = a;
2'b01: y = b;
2'b10: y = c;
default: y = 1'b0; // safety net
endcase
end
default를 추가하면 출력이 항상 정의되어 설계의 견고성이 향상됩니다.하나의 블록에서 여러 신호 제어
단일 always 블록에서 여러 신호를 제어할 때, 할당 순서와 누락된 경우가 의도치 않은 종속성을 만들 수 있습니다. 복잡한 설계에서는 명확성과 안전성을 위해 로직을 여러 always 블록으로 나누는 것을 고려하십시오.일반적인 함정약
| Problem | 원인 | Solution |
|---|
| 출력이 업데이트되지 않음 | 감도 목록에 누락된 신호 | 자동 감지를 위해 @(*)를 사용하십시오 |
| 래치 생성됨 | 모든 분기가 값을 할당하는 것은 아닙니다 | 항상 else 또는 default을 포함하십시오 |
| 정의되지 않은 동작 | Case 문에 조건이 없습니다 | 추가 default 브랜치 |
| 과도하게 복잡한 제어 | 하나의 블록에 신호가 너무 많습니다 | 여러 always 블록으로 나눕니다 |
5. SystemVerilog에서 always의 확장
always_comb: 조합 논리용
개요
always_comb는 always @(*)와 유사하게 동작하지만 조합 논리임을 명시적으로 나타냅니다.always_comb begin
y = a & b;
end
주요 장점
- 자동으로 민감도 리스트를 생성합니다
- 툴이 의도치 않은 래치가 추론될 때 경고합니다
- 이전에 정의된 변수와의 충돌을 방지합니다
예시 (Verilog vs SystemVerilog)
// Verilog
always @(*) begin
y = a | b;
end
// SystemVerilog
always_comb begin
y = a | b;
end
always_ff: 순차 논리(플립플롭)용
개요
always_ff는 클럭 구동 순차 논리를 위해 설계되었으며, posedge clk 또는 negedge rst와 같은 명시적인 엣지 조건이 필요합니다.always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n)
q <= 1'b0;
else
q <= d;
end
주요 장점
- 비블로킹 할당(
<=)만 허용합니다 - 툴이 민감도 리스트의 정확성을 검사합니다
- 코드 가독성이 향상되어 순차적임이 명확해집니다
always_latch: 래치 기반 논리용
개요
always_latch는 래치 동작을 의도적으로 기술할 때 사용됩니다. 그러나 대부분의 설계에서는 의도치 않은 래치를 피해야 합니다.always_latch begin
if (enable)
q = d;
end
유의사항
- 일부 분기에서 할당을 생략하면 래치가 명시적으로 생성됩니다
- 래치가 정말 필요할 때만 사용하십시오
SystemVerilog 사용 요약
| Construct | 목적 | Equivalent in Verilog | 기능 |
|---|
always_comb | 조합 논리 | always @(*) | 자동 감도 목록, 래치 감지 |
always_ff | 플립플롭 | always @(posedge clk) | 클럭 동기식, 더 안전한 할당 |
always_latch | 걸쇠 | always @(*) | 명시적 래치 설계, 오류 감지 |
SystemVerilog가 표준이가고 있습니다
현대 개발에서는 가독성과 안전성을 위해 SystemVerilog 구문이 점점 더 권장되고 있습니다. 향상된 구문 검사를 통해 always_ff와 always_comb을 사용하면 “맞는 것처럼 보이지만 동작하지 않는다”는 문제를 방지할 수 있습니다. 특히 대규모 또는 팀 기반 프로젝트에서는 명시적인 구문이 설계 의도를 명확히 하여 코드 리뷰와 유지보수성을 향상시킵니다.
6. FAQ: always 블록에 대한 일반적인 질문
이 섹션에서는 Verilog와 SystemVerilog의 always 블록에 대한 자주 묻는 질문에 답변하며, 설계 프로젝트에서 자주 발생하는 실용적인 문제에 초점을 맞춥니다. 실제 개발에서 흔히 보이는 초급부터 중급까지의 일반적인 이슈를 다룹니다.Q1. always 블록 안에서 if와 case 중 무엇을 사용해야 할까요?
A. 조건의 수와 복잡도에 따라 다릅니다:- 2~3개의 간단한 조건 →
if가 읽기 쉽습니다 - 여러 개의 구별되는 상태 →
case가 더 명확하고 의도를 잘 표현합니다
case를 사용하면 가능한 모든 경우를 다루어야 한다는 기대가 강제되어 실수를 줄이는 데 도움이 됩니다.Q2. 민감도 리스트에서 신호를 누락하면 어떻게 되나요?
A. 민감도 리스트가 불완전하면 일부 신호 변화가 블록을 트리거하지 않아 출력이 오래된 상태로 남게 됩니다. 이는 시뮬레이션과 합성 간 불일치를 초래할 수 있습니다. 이를 방지하려면 항상 @(*) 또는 SystemVerilog always_comb을 사용하십시오.Q3. 설계에 의도치 않은 래치가 나타나는 이유는 무엇인가요?
A. if 또는 case 문이 모든 가능한 경로에서 변수에 값을 할당하지 않으면, 합성 툴은 값을 유지해야 한다고 추론하여 래치를 생성합니다.나쁜 예시:
always @(*) begin
if (en)
y = d; // y is held when en == 0
end
해결책:
always @(*) begin
if (en)
y = d;
else
y = 1'b0; // always assigned
end
Q4. 동일 블록에서 =와 <=를 혼용할 수 있나요?
A. 일반적으로 아니오. 같은 블록, 특히 같은 신호에서 블로킹 할당과 논블로킹당을 혼합하면 시뮬레이션은 동작하지만 하드웨어는 실패할 수 있습니다.- 조합 논리 →
= (블로킹) 사용 - 순차 논리 →
<= (논블로킹) 사용
경험 법칙:
신호당 일관된 할당 방식을 항상 사용하세요.Q5. always_ff와 always @(posedge clk)의 차이점은 무엇인가요?
A. 기능적으로는 동일하게 동작하지만 always_ff가 더 안전하고 가독성이 좋습니다.| 비교 | always @(posedge clk) | always_ff |
|---|
| 감도 | 수동으로 지정해야 합니다 | 자동으로 확인됨 |
| 과제 오류 | 블로킹 할당은 컴파일될 수 있습니다. | 잘못된 할당은 오류를 일으킵니다 |
| 가독성 | 회로 의도를 흐릴 수 있음 | 순차 논리를 명확하게 나타냅니다 |
Q6. 하나의 always 블록에서 여러 신호를 제어해도 괜찮나요?
A. 가능하지만 신호가 너무 많으면 디버깅과 유지보수가 어려워집니다. 다음과 같은 경우 여러 블록으로 나누는 것을 고려하세요:- 각 출력이 독립적으로 동작할 때
- 동기식과 비동기식 로직을 혼합할 때
Q7. 조합 논리에서 <=를 사용하면 어떻게 되나요?
A. 시뮬레이션에서는 여전히 동작할 수 있지만, 합성 시 예기치 않은 로직이 생성될 수 있습니다. 조합 논리에서는 블로킹(=) 할당을 사용하세요.
7. 결론
always 블록은 Verilog 설계의 기반입니다
Verilog 하드웨어 설계에서 always 블록은 조합 회로와 순차 회로를 모두 기술할 수 있는 강력한 도구입니다. 설계 가능성을 넓혀줄 뿐만 아니라 제어 흐름과 타이밍을 명확히 합니다. 초보자든 전문가든 always는 필수 지식입니다.주요 요점
always @(*)와 always @(posedge clk)의 차이점 및 사용법=(블로킹)와 <=(논블로킹) 할당의 구분- 래치 생성 및 불완전한 민감도 리스트와 같은 일반적인 실수를 피하는 방법
- 보다 안전한 설계를 위한 SystemVerilog 확장(
always, always_ff, always_latch) - 실제 현장에서 자주 묻는 질문(FAQ)에 대한 실용적인 답변
정밀함이 품질을 결정합니다
하드웨어 기술에서 작성한 내용이 그대로 구현됩니다. 작은 실수도 하드웨어 버그가 될 수 있습니다. always가 동작의 핵심이므로 정확성, 올바른 할당 유형, 완전한 조건 커버리지가 중요합니다.다음 단계: 고수준 설계로 나아가기
always 블록을 마스터하면 다음으로 진행할 수 있습니다:- 유한 상태 머신(FSM) 설계
- 파이라인 및 스트리밍 아키텍처
- IP 코어 개발 및 FPGA 구현
또한 SystemVerilog와 VHDL을 학습하여 다양한 설계 환경에 적응할 수 있는 역량을 넓히세요.하드웨어 설계자를 위한 최종 생각
회로 설계는 단순히 “동작하게 만드는” 것이 아니라 올바른 동작, 향후 변경에 대한 견고함, 팀 개발을 위한 명확성이 필요합니다.
이 글을 통해 always 블록에 대한 기본 지식과 안전하고 신뢰할 수 있는 설계 관행에 대한 이해를 얻으셨길 바랍니다.