---
title: "데이터가 X여도 괜찮을까, valid 기반 초기화의 조건"
author: "브레이브브라우저쓰자"
published_at: "2026-10-07T00:46:00.322Z"
updated_at: "2026-10-05T13:49:09.734Z"
tags: ["valid 기반 초기화"]
canonical_url: "https://ariser.io/@writer_a9817d5a8de0/%EB%8D%B0%EC%9D%B4%ED%84%B0%EA%B0%80-x%EC%97%AC%EB%8F%84-%EA%B4%9C%EC%B0%AE%EC%9D%84%EA%B9%8C-valid-%EA%B8%B0%EB%B0%98-%EC%B4%88%EA%B8%B0%ED%99%94%EC%9D%98-%EC%A1%B0%EA%B1%B4"
ai_assisted: true
---

# 데이터가 X여도 괜찮을까, valid 기반 초기화의 조건

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

[원문](https://ariser.io/@writer_a9817d5a8de0/%EB%8D%B0%EC%9D%B4%ED%84%B0%EA%B0%80-x%EC%97%AC%EB%8F%84-%EA%B4%9C%EC%B0%AE%EC%9D%84%EA%B9%8C-valid-%EA%B8%B0%EB%B0%98-%EC%B4%88%EA%B8%B0%ED%99%94%EC%9D%98-%EC%A1%B0%EA%B1%B4)

reset 직후 파형에서 valid는 0인데 데이터 버스는 X다. 보기에는 초기화가 덜 된 회로 같지만, 이 상태가 항상 기능 오류인 것은 아니다. **valid 기반 초기화는 모든 데이터 비트를 같은 값으로 만드는 대신, 어떤 데이터가 의미 있는지를 제어 상태로 확정하는 방식**이다. 질문은 데이터가 0인가보다, 무효인 데이터가 동작에 사용될 수 있는가에 가깝다.

여기서는 한 개의 값을 저장하는 동기 버퍼를 생각하자. reset 중에는 거래를 세지 않고, reset 해제 이후에 입력 valid와 ready가 함께 높은 클록 에지에서만 새 데이터를 받는다고 정한다. 외부에서는 출력 valid가 높을 때만 data를 의미 있는 값으로 읽는 계약이다.

## 비어 있다는 사실부터 초기화하기

```systemverilog
assign in_ready  = !valid_q || out_ready;
assign out_valid = valid_q;
assign out_data  = data_q;

always_ff @(posedge clk or negedge rst_n) begin
  if (!rst_n)
    valid_q <= 1'b0;
  else if (in_ready)
    valid_q <= in_valid;
end

always_ff @(posedge clk) begin
  if (rst_n && in_valid && in_ready)
    data_q <= in_data;
end
```

data_q에는 reset 대입이 없다. reset을 거친 뒤 valid_q는 0이고 버퍼는 비어 있다. data_q가 어떤 값인지는 아직 정하지 않았다. 4-state 시뮬레이션에서는 X가 남을 수 있고 실제 회로의 전원 직후 값도 보장하지 않는다. 하지만 out_valid=0이므로 이 값은 유효한 출력이 아니다.

처음으로 in_valid=1, in_ready=1인 에지가 오면 data_q는 입력을 받고 valid_q도 1이 된다. 예를 들어 설명용 입력을 8'h52로 두면 에지 이후 유효한 출력은 0x52다. 이후 out_ready=0이고 버퍼가 차 있다면 in_ready=0이므로 데이터와 valid가 유지된다. out_ready=1인 동안 다음 입력도 유효하다면 현재 출력을 내보내면서 새 값으로 교체할 수 있다.

이 코드의 핵심 조건은 **valid가 1이 되는 에지에 해당 데이터도 실제로 기록된다**는 것이다. valid만 먼저 올리고 데이터 쓰기를 한 에지 미루면, 그 사이 오래된 데이터나 초기 X가 유효하다고 선언된다. reset을 생략해도 된다는 일반론이 아니라, 제어와 데이터의 정렬이 보장될 때의 기능 계약이다.

## 무효한 데이터가 비교기에 들어가면

데이터 경로의 일부가 X여도 그 결과를 사용하지 않으면 기능적으로 문제가 없을 수 있다. 그러나 data를 읽어 부작용을 만드는 경로가 valid를 빼먹으면 상황이 달라진다.

```systemverilog
assign is_command = (out_data == 8'hA5);
assign launch_bad = is_command;
assign launch_ok  = out_valid && is_command;
```

launch_bad는 버퍼가 비어 있어도 data_q의 잔여 값을 명령으로 해석할 수 있다. launch_ok는 출력의 의미가 있을 때만 비교 결과를 사용한다. reset으로 valid=0이 확정된 4-state 논리에서 `0 && X`는 0이므로, 무효 데이터의 불확실성이 이 동작을 켜지 못한다.

같은 원칙은 주소, 누적합, 인터럽트, 오류 상태에도 적용된다. 무효 payload가 출력에 보이는 것 자체와, 그 payload가 저장 상태를 바꾸는 것은 다르다. valid 기반 초기화를 선택했다면 데이터의 모든 의미 있는 소비 경로에 유효성 조건이 포함되어야 한다. 눈에 보이는 출력 하나만 가려서는 충분하지 않다.

[lowRISC의 X와 출력 검사 지침](https://github.com/lowRISC/style-guides/blob/master/VerilogCodingStyle.md#dont-cares-xs)은 초기의 무효 데이터와 실제 사용 시의 확정성을 구분하는 데 참고할 수 있다. 다음과 같이 유효 출력일 때만 데이터가 알려져 있어야 한다는 조건도 명시할 수 있다.

```systemverilog
assert property (@(posedge clk) disable iff (!rst_n)
  out_valid |-> !$isunknown(out_data));
```

이 assertion은 4-state 검사의 예다. 이것만으로 데이터가 기대한 값과 같다는 사실을 증명하지는 않는다. 유효한 데이터가 X가 아닌지와, 입력 순서대로 올바른 값이 나오는지는 별도 조건이다.

## 파형을 깨끗하게 만드는 reset의 비용

데이터 레지스터에도 reset을 넣으면 초기 파형이 더 읽기 쉬워진다. 요구하는 동작이 reset 후 data=0이라면 그렇게 해야 한다. 하지만 payload의 폭이 크고 valid=0일 때 데이터에 의미가 없다면, 초기 숫자를 일정하게 만들기 위해 모든 비트를 reset하는 것이 필수 기능은 아닐 수 있다.

구현에서는 reset 가능한 셀의 선택, reset 배선, fan-out과 타이밍 제약이 달라질 수 있다. 어느 쪽이 실제로 더 작고 빠른지는 라이브러리와 합성·배치 결과에 따라 결정된다. 위 예제가 reset 생략의 면적 절감 비율을 보장하는 것은 아니다. 먼저 기능상 필요한 초기 상태의 범위를 정하고, 그다음 구현상의 효과를 확인하는 순서가 맞다.

또 valid만 초기화하면 테스트벤치도 계약을 따라야 한다. 매 사이클 out_data를 정답 값과 비교하는 검사기는 버퍼가 비어 있는 동안 불필요하게 실패할 수 있다. 반대로 out_valid=1인 거래를 건너뛰면 진짜 문제를 놓친다. 검사는 유효한 출력의 값과 순서를 비교하되, invalid 구간에 데이터 안정성 요구가 있는지는 따로 판단해야 한다.

## 기능상 무효와 흔적 제거는 같은 요구가 아니다

valid=0은 “이 값으로 기능을 수행하지 않는다”는 선언이다. 데이터 비트가 실제로 지워졌다는 보장은 아니다. 이전 값을 읽을 수 있는 debug 경로가 있거나, 보안 요구가 잔여 데이터의 제거를 요구한다면 valid를 내리는 것만으로 충족되지 않는다. 그런 경우에는 초기화와 별개로 접근 제한 또는 삭제 동작이 필요할 수 있다.

또 reset 해제와 첫 입력이 맞물리는 경우, 클록 도메인이나 비동기 reset의 취급이 달라지는 경우에는 이 글의 단일 동기 버퍼 모델만으로 판단할 수 없다. reset 이후 유효성 제어가 알려진 상태인지, 데이터가 준비된 에지와 정확히 맞는지를 구현 조건에 맞게 확인해야 한다. [OpenTitan의 형식 검증 흐름](https://opentitan.org/book/hw/formal/) 같은 속성 기반 접근은 reset 뒤에 유효 데이터가 언제 생기는지 명시하는 데 유용하다.

처음의 X 버스는 이제 “reset이 없는 데이터”라는 표면만으로 평가하지 않는다. valid가 0으로 확정되어 있고, 그 상태에서는 어떤 소비자도 데이터를 동작에 쓰지 않으며, valid가 올라갈 때 새 데이터가 이미 기록된다면 기능 계약은 성립할 수 있다. **valid 기반 초기화의 정당성은 0으로 채운 비트 수가 아니라, 무효 상태를 끝까지 무효로 취급하는 회로의 일관성에 달려 있다.**

