Verilog 기초, Blocking과 Non-blocking에 대해서

 

Verilog의 세계: Blocking vs. Non-blocking Assignments, 그리고 그 너머

디지털 회로 설계의 세계에 오신 것을 환영합니다! Verilog HDL을 사용하여 하드웨어를 설계할 때, Blocking Assignment (=)와 Non-blocking Assignment (<=)는 마치 건반 위의 '도'와 '레'처럼 필수적이면서도 명확히 구분되는 역할을 합니다. 이 둘의 차이를 제대로 이해하는 것은 시뮬레이션 결과와 실제 구현될 하드웨어 간의 불일치를 막고, 원하는 기능을 정확하게 구현하는 데 핵심적입니다.

오늘은 이 두 가지 할당 방식의 차이점을 파헤치고, 이것이 어떻게 래치(Latch)와 플립-플롭(Flip-Flop)이라는 기본적인 메모리 요소와 연결되는지, 나아가 물리적인 수준까지 깊이 있게 탐구해보겠습니다.

1. Blocking Assignment (=)

"지금 당장 업데이트!" — Blocking assignment는 말 그대로 실행 순서를 막습니다. Verilog 코드 내에서 이 할당자를 만나면, 오른편(RHS)의 표현식이 계산되고 그 결과가 즉시 왼편(LHS) 변수에 할당됩니다. 이 할당이 완료된 후에야 다음 줄의 코드가 실행될 수 있습니다.

주요 특징:

  • 순차적 실행: 코드에 작성된 순서대로 실행되며, 이전 할당이 완료될 때까지 다음 할당은 기다립니다.
  • 즉각적인 값 반영: 할당된 새로운 값은 같은 프로시저 블록 내의 다음 문장에서 즉시 사용할 수 있습니다.
  • 주요 용도: 주로 조합 논리(Combinational Logic)를 모델링할 때 사용됩니다. always @(*) 블록이나 always_comb 블록 안에서 변수나 신호에 값을 할당할 때 유용합니다.

예시:

always @(*) begin
  // 'a'는 즉시 업데이트되고,
  a = in1 & in2;
  // 'b'는 업데이트된 'a'의 값을 사용하여 계산됩니다.
  b = a | in3;
end

이 예시에서 a가 먼저 계산되어 즉시 업데이트되면, b는 그 새로운 a 값을 즉시 읽어와서 계산됩니다.

2. Non-blocking Assignment (<=)

"잠시 기다렸다가, 다 같이 업데이트!" — Non-blocking assignment는 하드웨어의 동시성을 모델링하기 위해 설계되었습니다. always @(posedge clk)와 같은 클럭 동기 블록에서 주로 사용되며, 모든 Non-blocking assignment는 현재 시뮬레이션 시간 단계의 끝에서 일괄적으로 업데이트됩니다.

주요 특징:

  • 동시적 업데이트: 블록 내 모든 Non-blocking assignment의 RHS는 현재 시점의 변수 값(업데이트 전 값)으로 먼저 평가됩니다.
  • 지연된 할당: 실제 LHS 변수 값의 업데이트는 해당 시뮬레이션 시간 단계가 끝날 때까지 연기됩니다.
  • 주요 용도: 순차 논리(Sequential Logic), 즉 레지스터나 플립-플롭과 같은 메모리 요소를 모델링하는 데 필수적입니다. 클럭의 특정 엣지(상승/하강)에 맞춰 상태가 변하도록 설계할 때 사용됩니다.
  • 레이스 컨디션 방지: 값의 동시 업데이트 덕분에, 여러 신호 간의 복잡한 상호 의존성이 있는 순차 논리에서 발생할 수 있는 레이스 컨디션(Race Condition)을 효과적으로 방지합니다.

예시:

always @(posedge clk) begin
  q1 <= d_in;  // d_in 값은 이 클럭 엣지에서 q1에 할당될 예정입니다.
  q2 <= q1;    // q1의 값은 이전 클럭 엣지의 값이 사용됩니다.
  q3 <= q2;    // q2의 값은 이전 클럭 엣지의 값이 사용됩니다.
end

이 코드는 전형적인 시프트 레지스터를 모델링합니다. 각 클럭 엣지마다 d_in의 값이 q1으로, 이전 q1 값이 q2로, 이전 q2 값이 q3로 전달됩니다. 만약 여기서 Blocking assignment (=)를 사용했다면, q1이 업데이트된 직후 q2가 그 새 q1 값을 받아버리는 등 예상치 못한 결과가 발생할 수 있습니다.

3. Latch vs. Flip-Flop: 물리적 연결고리

Blocking assignment와 Non-blocking assignment의 차이는 우리가 Verilog 코드로 무엇을 '묘사'하고, 그 묘사가 실제 물리적인 하드웨어로 어떻게 '구현'되는지에 대한 중요한 단서를 제공합니다.

래치 (Latch)

  • 동작 방식: 래치는 레벨 민감(Level-Sensitive) 소자입니다. 즉, 'Enable' 신호가 특정 레벨(높거나 낮음)로 활성화되어 있는 동안에는 입력 값의 변화가 출력에 즉시 반영됩니다. Enable 신호가 비활성화되면, 래치는 마지막으로 가지고 있던 값을 계속 유지합니다.
  • 물리적 구현: 기본적인 래치는 크로스 커플링된 NOR 또는 NAND 게이트 쌍으로 구성될 수 있습니다. Enable 신호에 따라 게이트의 출력이 고정되거나 입력 신호를 따라가도록 설계됩니다.
  • Verilog에서의 추론:
    • 주로 always @(*) 블록에서 모든 가능한 입력 조건에 대해 항상 출력을 할당해주지 않으면 래치가 추론될 수 있습니다. 예를 들어 if-else 문에서 특정 조건에서만 출력이 할당되고, 나머지 조건에서는 할당되지 않는 경우, 합성 도구는 해당 출력이 이전 값을 '유지'해야 한다고 판단하여 래치를 삽입합니다.
    • 이는 의도치 않은 래치(unintended latch)를 만들 수 있으며, 이는 타이밍 문제나 예상치 못한 동작의 원인이 됩니다. 따라서 조합 논리에서는 모든 출력에 대해 항상 값을 할당하는 것이 중요합니다.
    • SystemVerilog의 always_latch 키워드를 사용하면 의도적으로 래치를 모델링할 수 있습니다.

플립-플롭 (Flip-Flop)

  • 동작 방식: 플립-플롭은 엣지 트리거(Edge-Triggered) 소자입니다. 즉, 클럭 신호의 특정 엣지(상승 엣지 posedge 또는 하강 엣지 negedge)에서만 입력 값을 받아들이고, 그 값을 저장했다가 다음 엣지까지 유지합니다.
  • 물리적 구현: 플립-플롭은 일반적으로 두 개의 래치를 직렬로 연결한 마스터-슬레이브(Master-Slave) 구조로 구현됩니다. 마스터 래치가 클럭의 한 엣지에서 값을 캡처하고, 슬레이브 래치가 클럭의 반대 엣지에서 마스터의 값을 출력으로 내보냅니다. 이 구조 덕분에 플립-플롭은 클럭 엣지 사이에는 투명하지 않고(non-transparent), 오직 엣지에서만 상태가 변합니다.
  • Verilog에서의 추론:
    • always @(posedge clk) 또는 always @(negedge clk)와 같이 클럭 엣지를 명시하는 always 블록에 Non-blocking assignment (<=)를 사용하면 플립-플롭이 정확하게 모델링됩니다.
    • SystemVerilog의 always_ff 키워드는 플립-플롭 모델링을 위한 명확한 방법으로, 합성 도구에 의해 플립-플롭으로 인식되도록 도와줍니다.

Blocking/Non-blocking과 Latch/Flip-Flop의 관계

  • Blocking (=) + always @(*) → 조합 논리: Blocking assignment와 always @(*) (모든 입력 변화에 반응)의 조합은 결과적으로 조합 논리 회로(AND, OR 게이트, 멀티플렉서 등)를 생성합니다. 여기서 지연은 순전히 게이트의 전달 지연(propagation delay)으로만 발생합니다.
  • Non-blocking (<=) + always @(posedge clk) → 플립-플롭: Non-blocking assignment와 클럭 엣지 민감 블록의 조합은 표준적인 플립-플롭 회로를 생성합니다. 값은 클럭 엣지에서 저장되며, 시간은 클럭 주기라는 명확한 단위로 나뉩니다.
  • 의도치 않은 래치: always @(*) 블록에서 일부 출력에 대한 할당을 누락하면, 래치가 생성되어 회로에 의도치 않은 메모리 요소가 삽입될 수 있습니다. 래치는 클럭 엣지가 아닌 레벨에 반응하기 때문에, 특히 동기 설계에서 예측하기 어려운 타이밍 문제를 일으킬 수 있습니다.

요약하자면, Verilog에서의 Blocking Assignment는 '순간적인 반응'을, Non-blocking Assignment는 '동기화된 순간의 반응'을 모델링하며, 이러한 설계 방식이 궁극적으로는 조합 논리, 래치, 플립-플롭이라는 물리적인 하드웨어 구성 요소로 변환됩니다. 설계자는 이 두 가지 할당 방식의 차이를 명확히 인지하고 적재적소에 활용함으로써, 안정적이고 효율적인 디지털 회로를 구현할 수 있습니다.

📚 참고 자료

댓글

이 블로그의 인기 게시물

📚 SDC 마스터 클래스 시리즈 | Chapter 1

📚 SDC 마스터 클래스 시리즈 | Chapter 2

📚 SDC 마스터 클래스 시리즈 | Chapter 3