블로킹 할당 vs 논블로킹 할당: 평가 타이밍·순서·사용 위치 비교

둘 다 Verilog always 블록 안에서 쓰는 할당이지만, 좌변이 바뀌는 타이밍이 다릅니다. 블로킹 할당(=)은 그 줄을 실행한 시점에 좌변을 갱신하며, 다음 줄에서는 새 값이 쓰입니다. 논블로킹 할당(<=)은 같은 타이밍의 모든 우변을 먼저 평가한 뒤 좌변을 한꺼번에 갱신합니다. 클럭으로 동작하는 순차 회로에는 <=, 조합 회로의 always에는 =를 쓰는 것이 기본 가이드라인입니다.

비교 항목블로킹 할당(=)논블로킹 할당(<=)
작성법a = b;a <= b;
좌변을 갱신하는 타이밍그 줄을 실행할 때 즉시 갱신합니다같은 타이밍의 우변을 모두 평가한 뒤 한꺼번에 갱신합니다
다음 줄에서 보이는 값갱신 후의 새 값갱신 전의 이전 값
기술 순서에 대한 의존성있음. 줄 순서를 바꾸면 결과가 달라집니다거의 없음. 단, 같은 변수에 두 번 할당하면 나중 할당이 남습니다
대응하는 회로 동작위에서부터 차례로 중간값을 계산해 나가는 조합 회로클럭 에지에서 일제히 값을 받아들이는 플립플롭
주로 쓰는 위치조합 회로의 always @(*), 테스트벤치의 절차클럭으로 동작하는 순차 회로의 always @(posedge clk)
2단 시프트 레지스터(클럭으로 동작하는 블록)q1 = d; q2 = q1;에서는 q2에도 같은 에지에서 d가 들어가 1단만 지연됩니다q1 <= d; q2 <= q1;에서는 q2에 에지 이전의 q1이 들어가 2단이 됩니다
값 교환(클럭으로 동작하는 블록)a = b; b = a;에서는 a와 b가 같은 값이 됩니다a <= b; b <= a;에서는 a와 b가 서로 바뀝니다
여러 always 블록 사이같은 에지에서 동작하는 블록끼리 실행 순서에 따라 결과가 달라지는 레이스가 생기기 쉽습니다우변 평가가 먼저 갖춰지므로 레이스가 잘 생기지 않습니다
잘못 사용했을 때순차 회로에 쓰면 결과가 블록 실행 순서에 좌우되어, 합성된 회로와 동작이 어긋날 수 있습니다조합 회로에 쓰면 중간값이 이전 값인 채로 읽혀, 시뮬레이션이 합성된 회로와 어긋나거나 불필요하게 재실행됩니다

수치는 대략적인 자릿수 기준이며, 공정 세대와 제품에 따라 달라져요.

상황별 선택 기준

블로킹 할당(=)
조합 회로의 always @(*) 안에서 중간값을 차례로 계산할 때. 테스트벤치에서 절차를 순서대로 작성할 때.
논블로킹 할당(<=)
always @(posedge clk) 등 클럭으로 동작하는 플립플롭을 작성할 때. 레지스터, 카운터, 상태 기계의 상태 갱신.
섞지 않기
하나의 always 블록 안에서 =와 <=를 섞지 않고, 같은 변수를 여러 always 블록에서 할당하지 않도록 합니다. SystemVerilog에서는 always_ff와 always_comb로 의도를 도구에 전달할 수 있습니다.

자주 묻는 질문

순차 회로에 블로킹 할당을 쓰면 어떻게 되나요?

줄 순서에 따라서는 같은 에지에서 갱신한 값이 다음 줄로 그대로 넘어가, 의도보다 단수가 적은 회로가 됩니다. 또한 같은 클럭으로 동작하는 다른 always 블록과의 사이에서 실행 순서에 따라 결과가 달라지는 레이스가 생겨, 시뮬레이션과 합성된 회로가 어긋나는 원인이 됩니다.

논블로킹 할당으로 a <= b; b <= a;라고 쓰면 값이 서로 바뀌는 이유는 무엇인가요?

두 우변을 이전 값인 채로 먼저 평가한 뒤 좌변을 한꺼번에 갱신하기 때문입니다. 두 플립플롭의 출력을 서로의 입력에 연결한 회로와 같은 동작이 됩니다.

테스트벤치에서는 어느 쪽을 써야 하나요?

절차를 순서대로 작성하는 부분은 블로킹 할당을 써도 됩니다. 다만 회로 입력을 클럭 에지와 같은 시각에 바꾸면, 이전 값과 새 값 중 어느 것을 받아들일지가 실행 순서에 따라 달라지므로, 에지에서 조금 어긋나게 하거나 논블로킹 할당으로 바꿉니다.

이해도 확인

Verilog의 논블로킹 대입(<=)의 동작으로 올바른 것은?

  1. A대입한 순간 좌변이 갱신되고, 다음 줄에서는 그 새로운 값이 사용된다
  2. B같은 타이밍의 모든 우변을 먼저 평가한 뒤, 그 후에 좌변을 한꺼번에 갱신한다
  3. C대입 결과를 버리고 아무것도 변경하지 않는다
정답과 해설 보기

정답: B. 같은 타이밍의 모든 우변을 먼저 평가한 뒤, 그 후에 좌변을 한꺼번에 갱신한다

논블로킹 대입에서는 클럭 에지에서 모든 <=의 우변을 먼저 이전 값 그대로 평가한 뒤, 그 후에 일제히 좌변을 갱신합니다. 이는 같은 클럭으로 동작하는 다수의 플립플롭이 에지 직전의 값을 동시에 받아들이는 실제 회로의 동작과 같습니다. 따라서 클럭으로 동작하는 순서 회로의 기술에는 논블로킹 대입을 사용하는 것이 원칙입니다.

Verilog에서 대입의 종류를 구분하여 사용할 때의 일반적인 가이드라인으로 올바른 것은?

  1. A어디서나 블로킹 대입(=)만 사용한다
  2. B클럭으로 동작하는 순서 회로에는 논블로킹 대입(<=), 조합 회로의 always에는 블로킹 대입(=)을 사용한다
  3. C하나의 always 안에서 둘을 무작위로 섞어 사용한다
정답과 해설 보기

정답: B. 클럭으로 동작하는 순서 회로에는 논블로킹 대입(<=), 조합 회로의 always에는 블로킹 대입(=)을 사용한다

순서 회로를 논블로킹 대입으로 작성하면 모든 플립플롭이 동시에 값을 받아들이는 회로의 동작과 일치하며, 기술 순서나 다른 always 블록과의 실행 순서에 결과가 좌우되지 않습니다. 조합 회로에서는 위에서부터 차례로 중간 값을 계산해 가는 방식이 자연스러우므로 블로킹 대입을 사용합니다. 하나의 always 블록 안에서 둘을 섞지 않는 것도 중요합니다.

테스트벤치에서 회로에 대한 입력을 클럭 상승과 같은 시각에 블로킹 대입으로 바꾸면 문제가 생길 수 있다. 주된 이유와 대책의 조합으로 올바른 것은?

  1. A회로가 바뀌기 전과 후 중 어느 값을 받아들이는지가 실행 순서에 따라 달라지기(경합) 때문. 입력은 클럭 에지에서 조금 어긋나게 하거나 논블로킹 대입으로 바꾼다
  2. B클럭의 주파수가 자동으로 낮아지기 때문. 클럭을 빠르게 한다
  3. C블로킹 대입은 테스트벤치에서는 사용할 수 없기 때문. 모두 assign문으로 한다
정답과 해설 보기

정답: A. 회로가 바뀌기 전과 후 중 어느 값을 받아들이는지가 실행 순서에 따라 달라지기(경합) 때문. 입력은 클럭 에지에서 조금 어긋나게 하거나 논블로킹 대입으로 바꾼다

같은 시각에 테스트벤치가 입력을 갱신하는 처리와 회로의 플립플롭이 입력을 받아들이는 처리가 일어나면, 시뮬레이터가 어느 쪽을 먼저 실행하느냐에 따라 받아들여지는 값이 이전 값이 되기도 하고 새로운 값이 되기도 합니다. 이는 시뮬레이션의 경합(레이스)이며 시뮬레이터에 따라 결과가 달라지기도 합니다. 입력을 하강 에지에서 바꾸거나, 조금 지연시키거나, 논블로킹 대입이나 SystemVerilog의 클로킹 블록을 사용하는 등으로 방지합니다.

  1. 위의 기술에서 클럭 상승 직전에 a=0, b=1이었다. 상승 후의 a와 b의 값은 어떻게 됩니까?
  2. 2단 시프트 레지스터를 의도하여 위와 같이 블로킹 대입(=)으로 작성했다. 발생하는 문제로 올바른 것은?
  3. 조합 회로를 의도하여 위와 같이 작성했다. 발생할 수 있는 문제로 올바른 것은?

HDL과 검증 문제 풀기

주요 용어 설명

블로킹 할당(blocking assignment)
Verilog의 "=" 할당. 그 자리에서 좌변이 갱신되어 다음 줄에서 그 새 값이 사용된다. 조합 회로의 always와 테스트벤치에서 쓴다.
논블로킹 대입(Non-blocking Assignment)
Verilog의 "<=" 대입. 같은 타이밍의 모든 우변을 먼저 평가한 뒤 한꺼번에 좌변을 갱신한다. 플립플롭의 동작과 일치하므로 순차 회로에 사용한다.
민감도 목록(Sensitivity List)
Verilog의 always 뒤 @( )에 쓰는, 블록을 실행하는 계기가 되는 신호의 나열. 조합 회로에서 빠뜨리면 시뮬레이션과 회로가 어긋난다.
Verilog
디지털 회로의 설계와 검증에 널리 사용되는 하드웨어 기술 언어. module을 단위로 회로를 쓰고 assign과 always로 동작을 나타낸다.

관련 비교