---
title: "Gray 포인터의 한 비트 규칙은 배선에서도 지켜질까"
author: "브레이브브라우저쓰자"
published_at: "2026-10-09T10:06:02.852Z"
updated_at: "2026-10-05T23:49:43.693Z"
tags: ["gray 포인터"]
canonical_url: "https://ariser.io/@writer_a9817d5a8de0/gray-%ED%8F%AC%EC%9D%B8%ED%84%B0%EC%9D%98-%ED%95%9C-%EB%B9%84%ED%8A%B8-%EA%B7%9C%EC%B9%99%EC%9D%80-%EB%B0%B0%EC%84%A0%EC%97%90%EC%84%9C%EB%8F%84-%EC%A7%80%EC%BC%9C%EC%A7%88%EA%B9%8C"
ai_assisted: true
---

# Gray 포인터의 한 비트 규칙은 배선에서도 지켜질까

이 글은 AI가 활용됐습니다.

[원문](https://ariser.io/@writer_a9817d5a8de0/gray-%ED%8F%AC%EC%9D%B8%ED%84%B0%EC%9D%98-%ED%95%9C-%EB%B9%84%ED%8A%B8-%EA%B7%9C%EC%B9%99%EC%9D%80-%EB%B0%B0%EC%84%A0%EC%97%90%EC%84%9C%EB%8F%84-%EC%A7%80%EC%BC%9C%EC%A7%88%EA%B9%8C)

“한 번에 한 비트만 바뀌니까 안전하다.” Gray 포인터를 설명할 때 자주 듣는 문장이다. 논리적으로는 중요한 성질이지만, 배선이 서로 다른 시간에 변화를 전달하면 그 문장만으로 충분하지 않다. **Gray 포인터는 인접한 원천 값의 변화 수를 줄이는 표현이며, 그 인접성은 구현의 도착 시간에서도 유지되어야 한다.**

Gray code는 연속된 값 사이에 비트 하나만 달라지는 부호다. 비동기 FIFO에서 로컬 읽기·쓰기 위치를 상대 클록 영역으로 알릴 때 사용한다. 이 글에서는 저장 배열 자체보다, 그 위치 정보를 어떤 값으로 믿을 수 있는지에 집중하자.

## 이진 전이와 Gray 전이를 나란히 보기

4비트 이진 포인터 b의 Gray 값은 다음처럼 만들 수 있다.

`g = b XOR (b >> 1)`

이진수 3은 0011, 4는 0100이다. 3→4에서 세 비트가 바뀐다. 반면 Gray 값은 3에서 0010, 4에서 0110이므로 bit2 하나만 달라진다. 각 비트를 목적지에서 동기화할 때 해당 전이에서 불확실할 수 있는 값이 인접한 두 위치로 제한될 수 있다는 점이 유리하다.

원천 포인터는 등록된 값이어야 한다. 조합 이진 카운터의 여러 비트가 물리적으로 동시에 바뀌지 않는 동안 Gray 변환 논리가 글리치를 만들면, “등록된 Gray 값이 한 비트만 바뀐다”는 전제가 그대로 적용되지 않는다. 설명용으로 다음 상태에서 Gray를 계산해 원천 에지에 함께 등록할 수 있다.

```systemverilog
assign binary_next = binary_q + 4'd1;

always_ff @(posedge src_clk) begin
  if (advance) begin
    binary_q <= binary_next;
    gray_q <= binary_next ^ (binary_next >> 1);
  end
end
```

이 조각은 초기화와 FIFO의 수락 조건을 생략한 4비트 예제다. 상대에게 전달하는 것은 등록된 gray_q이고, 로컬 주소 계산은 binary_q로 수행할 수 있다. 전체 FIFO 포인터는 깊이와 wrap 구분에 필요한 비트 수를 따로 정해야 한다.

## 서로 다른 두 전이가 배선에서 겹치면

원천 포인터가 2→3→4로 진행한다고 하자. Gray 값은 0011→0010→0110이다. 첫 전이에서는 bit0이 내려가고 다음 전이에서는 bit2가 올라간다. 각 원천 에지에서 변화는 하나뿐이다.

가상의 배선 지연을 넣어 보자. 첫 전이가 0ns에 발생했는데 bit0의 하강은 목적지에 25ns 뒤에 도착한다. 다음 전이는 10ns에 발생하고 bit2의 상승은 1ns 뒤인 11ns에 도착한다. 원천 클록 주기는 10ns라는 가정이다.

11ns부터 25ns 사이에는 목적지에서 bit2의 새 1과 bit0의 오래된 1이 함께 보인다. 수신 버스는 0111이 된다. 이 Gray 값은 이진 위치 5를 뜻한다. 원천은 아직 위치 4까지밖에 진행하지 않았는데 상대가 미래 위치를 본 셈이다.

이런 혼합은 Gray 패턴이 틀렸다는 단순 검사로 발견하기 어렵다. 4비트 패턴 0111 자체는 정상적인 Gray 표현이다. 문제는 그 값이 해당 원천의 진행 이력에서 지금 가능한 값이 아니라는 데 있다. **각 에지의 한 비트 변화와, 서로 다른 전이가 목적지에 순서대로 도착한다는 조건은 따로 필요하다.**

## skew 제약이 지키는 것은 전이의 경계다

skew는 관련 비트 경로들 사이의 상대적인 도착 시간 차이다. 이전 전이의 느린 비트가 다음 전이의 빠른 비트보다 뒤늦게 도착하지 않도록 제한하면, 여러 원천 전이가 뒤섞이는 위험을 줄일 수 있다. 필요한 한계는 원천 포인터의 최소 변경 간격과 타이밍 여유에 맞춰야 한다.

[Altera의 dual-clock FIFO 제약 설명](https://docs.altera.com/r/docs/683082/25.1/quartus-prime-pro-edition-user-guide/dual-clock-fifo-timing-constraints)은 Gray 포인터의 올바른 전달을 위해 skew 제약과 경로 지연 제약을 함께 다룬다. [PULP의 Gray CDC FIFO](https://github.com/pulp-platform/common_cells/blob/master/src/cc_cdc_fifo_gray.sv)도 비동기 경로에 max-delay 조건을 요구한다. 해당 구현의 조건을 실제 클록과 경로에 적용해야 하며, 모든 도구에서 같은 명령과 우선순위가 적용된다고 가정해서는 안 된다.

클록이 서로 비동기라는 이유로 정상적인 setup·hold 관계를 끊는 것과, 비트 간 도착 관계를 아무 제한 없이 두는 것은 다르다. 논리 검증에서 Gray 변환이 맞았다는 사실은 물리 제약의 대체물이 아니다.

## 목적지가 여러 위치를 건너뛰어도 되는 이유

느린 목적지는 원천의 모든 포인터 값을 볼 필요가 없을 수 있다. 원천이 여러 번 진행한 동안 목적지는 이전 위치와 그 뒤의 위치만 관측할 수 있다. 목적지의 두 연속 샘플 사이에 여러 비트가 달라졌다는 사실만으로 Gray의 원천 전이 규칙을 어긴 것은 아니다.

검사해야 할 대상은 원천의 인접한 등록값 사이의 한 비트 변화와, 상대가 믿는 포인터가 안전한 원천 값에서 왔다는 전달 조건이다. 목적지 샘플의 Hamming 거리를 항상 1로 강제하면 정상적인 빠른 원천·느린 목적지 실행까지 금지할 수 있다.

또 동기화 지연 때문에 상대 포인터는 보통 늦게 보인다. FIFO의 full·empty 제어는 그 지연된 정보에서도 넘치거나 없는 데이터를 읽지 않도록 보수적으로 동작해야 한다. 원문의 PULP 구현도 이 지연된 포인터를 기준으로 한 보수적인 상태를 설명한다. “최근 위치를 정확히 즉시 안다”는 프로토콜은 아니다.

## reset과 범위는 별도의 계약

Gray를 써도 한쪽 포인터만 reset되면 상대의 이전 위치와 관계가 깨질 수 있다. wrap 비트와 실제 배열 크기를 잘못 맞춰도 full·empty 의미가 틀어진다. Gray는 표현 방식의 한 성질을 제공할 뿐, 초기 상태와 용량 계약을 자동으로 정의하지 않는다.

검증에서도 원천 증가가 한 단계라는 조건을 확인해야 한다. 포인터를 임의 위치로 점프시키면 Gray 변환을 사용하더라도 여러 비트가 동시에 변할 수 있다. 정상 증가, 물리 도착 제약, reset과 wrap의 규칙이 같은 포인터를 설명해야 한다.

처음의 문장은 이제 조건을 더 붙여 읽게 된다. 원천에서 등록된 포인터가 한 단계씩 진행하고, 비트 경로가 서로 다른 전이를 겹치게 만들지 않으며, 상대는 동기화 지연을 감안해 사용해야 한다. **Gray 포인터의 안전성은 코드의 XOR 한 줄과 구현의 전이 경계를 함께 지킬 때 생긴다.** 한 비트만 바뀐다는 논리적 이점이 실제 회로의 이점이 되려면 도착 시간의 관계도 설계해야 한다.

