---
title: "reset 동기 해제: 초기값은 맞는데 첫 거래만 멈추는 이유"
author: "브레이브브라우저쓰자"
published_at: "2026-10-09T12:24:04.233Z"
updated_at: "2026-10-05T23:51:05.043Z"
tags: ["reset 동기 해제"]
canonical_url: "https://ariser.io/@writer_a9817d5a8de0/reset-%EB%8F%99%EA%B8%B0-%ED%95%B4%EC%A0%9C-%EC%B4%88%EA%B8%B0%EA%B0%92%EC%9D%80-%EB%A7%9E%EB%8A%94%EB%8D%B0-%EC%B2%AB-%EA%B1%B0%EB%9E%98%EB%A7%8C-%EB%A9%88%EC%B6%94%EB%8A%94-%EC%9D%B4%EC%9C%A0"
ai_assisted: true
---

# reset 동기 해제: 초기값은 맞는데 첫 거래만 멈추는 이유

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

[원문](https://ariser.io/@writer_a9817d5a8de0/reset-%EB%8F%99%EA%B8%B0-%ED%95%B4%EC%A0%9C-%EC%B4%88%EA%B8%B0%EA%B0%92%EC%9D%80-%EB%A7%9E%EB%8A%94%EB%8D%B0-%EC%B2%AB-%EA%B1%B0%EB%9E%98%EB%A7%8C-%EB%A9%88%EC%B6%94%EB%8A%94-%EC%9D%B4%EC%9C%A0)

전원을 켠 뒤 대부분의 레지스터는 정상적으로 움직인다. 그런데 가끔 상태 머신이 첫 거래에서만 멈춘다. reset을 충분히 오래 눌렀고, 논리 시뮬레이션에서도 문제가 없었다면 어디를 볼까. **reset 동기 해제는 초기값을 쓰는 문제가 아니라, 여러 상태 요소가 언제부터 같은 클록의 규칙을 따르기 시작하는지 정하는 문제**다.

여기서는 낮은 수준에서 활성화되는 rst_n과 상승 에지 클록을 가정한다. rst_n이 0이면 초기화 상태이고, 1로 올라가면 정상 동작을 허용한다. 문제는 그 상승이 클록과 아무 관계 없는 순간에 일어날 수 있다는 데 있다.

## reset의 끝에도 타이밍 조건이 있다

비동기 reset이 있는 플립플롭은 클록이 없어도 reset을 받아들일 수 있다. 하지만 reset을 해제한 직후의 클록까지 아무 시점이나 허용하는 것은 아니다. 셀에는 recovery와 removal 조건이 있다. 해제가 유효 클록 에지에 지나치게 가까우면 내부 상태가 안정적으로 초기화 모드에서 벗어났다고 보장하기 어렵다.

예를 들어 가상의 10ns 주기 클록이 0, 10, 20ns에 상승한다고 하자. 외부 reset은 9.9ns에 해제된다. 배선과 셀 차이로 어떤 레지스터는 10ns 에지에서 동작을 시작하고, 다른 레지스터는 아직 초기값에 머물거나 불확실한 전이를 겪을 수 있다. 수치는 설명용이며 실제 위반 여부는 해당 셀의 timing과 경로 분석으로 판단해야 한다.

상태 머신에서 상태 레지스터는 첫 요청을 받았는데 거래 카운터는 초기값에 남았다면, 각각의 값이 0이나 1로 안정되어도 두 상태의 관계는 틀릴 수 있다. reset을 오래 유지하는 것만으로 마지막 순간의 해제 위치를 제어할 수는 없다.

## 해제의 허가를 클록으로 전달하기

기본 구조는 reset의 assertion은 비동기적으로 받아들이고, deassertion은 클록 에지를 거쳐 전달한다. 아래 코드는 원리를 보이는 2단 예제다.

```systemverilog
logic [1:0] release_q;

always_ff @(posedge clk or negedge ext_rst_n) begin
  if (!ext_rst_n)
    release_q <= 2'b00;
  else
    release_q <= {release_q[0], 1'b1};
end

assign local_rst_n = release_q[1];
```

외부 reset이 해제된 뒤 첫 정상 샘플링 에지에서 release_q는 01, 다음 에지에서 11이 된다. local_rst_n은 두 번째 에지 뒤에 올라간다. local_rst_n을 비동기 reset으로 쓰는 기능 레지스터는 그 두 번째 에지를 이미 reset 상태로 지나갔으므로, 보통 다음 유효 에지부터 정상 갱신을 시작한다. 출력이 에지에 맞춰 바뀌는 것과 같은 에지에서 소비자가 새 값을 쓴다는 것은 다르다.

[PULP의 reset synchronizer 구현](https://github.com/pulp-platform/common_cells/blob/master/src/cc_rstgen_bypass.sv)은 여러 레지스터에 1을 이동시키는 구조와 별도의 test bypass를 사용한다. 확인한 구현의 기본 단계 수는 4다. 위 예제의 2단은 원리 설명이며, 필요한 단계 수를 모든 칩에 고정하는 권장값이 아니다. 셀 특성, 주파수, 목표 신뢰도와 배치 조건에 맞춰 정해야 한다.

## 같은 reset을 여러 번 동기화하면 같은 출발선일까

같은 클록을 사용하는 관련 상태에 각각 독립적인 동기화기를 달면, 외부 해제가 경계에 가까울 때 출력 해제 사이클이 달라질 수 있다. 첫 단계가 reset 해제를 어느 에지에서 받아들이는지에 따라 한쪽이 더 늦어질 수 있기 때문이다.

따라서 서로 일치해야 하는 기능 상태에는 하나의 일관된 local reset을 배포하는 구성이 유리하다. 다만 출력의 큰 fan-out과 reset 배선 지연을 함께 관리해야 한다. 논리적으로 같은 신호라는 이유로 물리 배포 문제가 없어지는 것은 아니다. 각 도메인의 local reset을 만드는 구조, reset tree의 지연, 기능 플립플롭의 recovery·removal 검사를 같은 설계로 연결해야 한다.

서로 다른 클록 도메인은 각자의 클록으로 해제해야 한다. 그 결과 두 영역이 같은 실제 시각에 동작을 시작할 필요는 없다. 통신을 시작하기 전에 상대가 준비되었음을 확인해야 하는 인터페이스라면, reset synchronizer 뒤에도 준비 상태의 계약이 필요하다.

## 클록이 멈추어 있다면 해제도 기다린다

위 구조에서 클록이 정지하면 1이 이동하지 않으므로 local reset은 계속 활성화된다. 이것은 구현 오류가 아니라 동기 해제의 직접적인 결과다. 전원 관리가 기능 클록을 먼저 막고, 기능 블록이 reset을 벗어난 뒤 클록을 요청하도록 설계했다면 서로 기다리는 구조가 될 수 있다.

해결에는 클록 공급 순서가 포함되어야 한다. 먼저 초기화를 진행할 클록을 제공하고, 정해진 에지가 지난 뒤 기능 동작을 허용하는 식이다. 테스트 모드에서 synchronizer를 우회한다면 그때의 reset timing도 별도로 정의해야 한다. 기능 모드의 안전성을 bypass 경로에 그대로 적용할 수 없다.

또 reset이 너무 짧아 내부 셀까지 유효하게 전달되지 않는 문제는 해제 동기화와 별개다. assertion의 최소 펄스 폭과 reset 배포 조건은 여전히 필요하다. 동기화기를 넣었다는 한 줄이 reset 전체의 검증을 대신하지 않는다.

첫 거래에서만 생기던 멈춤을 조사할 때는 초기값 목록 다음에 출발 에지를 봐야 한다. **관련 상태가 같은 local reset으로, 자신의 클록에서, 실제 셀의 해제 조건을 만족하며 정상 모드에 들어오는가**가 판단 기준이다. reset 동기 해제는 시작을 몇 사이클 늦추는 대신, 정상 동작의 첫 사이클부터 상태 관계를 지킬 수 있게 만든다.

