---
title: "constraint overrestriction: seed를 바꿔도 마지막 주소가 나오지 않는 이유"
author: "브레이브브라우저쓰자"
published_at: "2026-10-18T07:25:03.460Z"
updated_at: "2026-10-06T00:58:22.766Z"
tags: ["constraint overrestriction"]
canonical_url: "https://ariser.io/@writer_a9817d5a8de0/constraint-overrestriction-seed%EB%A5%BC-%EB%B0%94%EA%BF%94%EB%8F%84-%EB%A7%88%EC%A7%80%EB%A7%89-%EC%A3%BC%EC%86%8C%EA%B0%80-%EB%82%98%EC%98%A4%EC%A7%80-%EC%95%8A%EB%8A%94-%EC%9D%B4%EC%9C%A0"
ai_assisted: true
---

# constraint overrestriction: seed를 바꿔도 마지막 주소가 나오지 않는 이유

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

[원문](https://ariser.io/@writer_a9817d5a8de0/constraint-overrestriction-seed%EB%A5%BC-%EB%B0%94%EA%BF%94%EB%8F%84-%EB%A7%88%EC%A7%80%EB%A7%89-%EC%A3%BC%EC%86%8C%EA%B0%80-%EB%82%98%EC%98%A4%EC%A7%80-%EC%95%8A%EB%8A%94-%EC%9D%B4%EC%9C%A0)

랜덤 테스트를 수천 번 돌렸는데 메모리 끝에 딱 맞는 전송은 한 번도 나오지 않았다. 운이 나빴을까. seed를 더 바꾸기 전에, 그 입력이 현재 constraint를 만족할 수 있는지 확인해야 한다. 합법적인 입력만 만든다는 사실과 필요한 합법 입력을 모두 만들 수 있다는 사실은 다르다.

constraint overrestriction은 유효한 입력 공간을 편의상 지나치게 좁혀 중요한 상황을 제외하는 문제다. solver가 매번 성공해도 이런 누락은 남을 수 있다.

## 편리한 정렬 조건이 합법 공간을 줄인다

가상의 256바이트 메모리 전송을 생각하자. 시작 주소는 0~255이고 길이는 1, 4, 8, 16바이트 중 하나다. 전송 끝이 256을 넘지 않으면 합법이며, 이 인터페이스는 정렬되지 않은 시작 주소도 지원한다고 정한다.

기본 입력 조건에 테스트 작성자가 편의를 위해 16바이트 정렬을 더하면 다음과 같다. 아래 변수는 덧셈이 8비트에서 잘려 나가는 문제를 피하도록 충분한 폭의 정수로 선언했다.

```systemverilog
rand int unsigned addr;
rand int unsigned length;
constraint legal_c {
  addr inside {[0:255]};
  length inside {1, 4, 8, 16};
  addr + length <= 256;
}
constraint convenience_c {
  addr % 16 == 0;
}
```

기본 조건의 가능한 쌍은 길이별로 256, 253, 249, 241개다. 합하면 999개다. 정렬 조건을 추가하면 시작 주소가 0, 16, …, 240으로 줄고, 이 16개 주소에서 네 길이가 모두 가능하므로 64개 쌍만 남는다.

이 64개는 모두 합법이다. 하지만 합법 쌍 935개가 생성 대상에서 사라졌다. 특히 `(addr=248, length=8)`은 끝이 정확히 256인 합법 전송이지만, 248이 16의 배수가 아니므로 절대 나오지 않는다. seed는 이 제외된 쌍을 되살릴 수 없다.

## 만족 가능성과 충분한 다양성은 별도 질문이다

UVM 가이드는 transaction의 constraint로 자극을 정의하고, 용도에 따라 추가 조건과 control knob를 제공하는 방법을 설명한다. constraint를 별도 블록으로 나누면 필요에 따라 재정의하거나 비활성화하기도 쉽다. 따라서 명세의 기본 합법 조건과 특정 테스트의 선호 조건을 구별해서 관리할 수 있다. [Accellera UVM User’s Guide 1.1, §3.1.1 및 §3.1.2](https://www.accellera.org/images/downloads/standards/uvm/uvm_users_guide_1.1.pdf)

현재 조건이 만족 가능하다는 것은 최소 하나의 해가 있다는 뜻이다. 64개 중 어떤 해를 성공적으로 만들었다고 해서 원래 999개를 모두 다룬 것은 아니다. constraint끼리 충돌해 해가 전혀 없는 문제와, 해는 있지만 필요한 영역을 잘라낸 문제를 나누어 진단해야 한다.

관심 입력을 직접 넣어 보는 작은 확인이 유용하다. 위 객체에 `addr==248`과 `length==8`을 추가하여 randomize하면 기본 조건은 만족하지만 convenience 조건과 충돌한다. 실패를 확인한 뒤 convenience 블록만 끄면 같은 쌍은 조건을 만족한다. 이 과정은 DUT가 그 입력에서 옳게 동작하는지에 대한 시험과 별도로, 자극 생성기가 그 입력을 허용하는지 확인하는 것이다.

randomize 반환값도 반드시 검사해야 한다. 실패를 무시한 채 객체의 이전 값을 재사용하면 ‘새 랜덤 입력을 만들었다’는 로그가 실제와 어긋난다. lowRISC의 DV 가이드는 randomize처럼 상태를 바꾸는 동작을 비활성화될 수 있는 assert 안에 넣지 말고, 반환 결과를 적절한 방식으로 확인하도록 권한다. [lowRISC DV Coding Style, Code Within Asserts](https://github.com/lowRISC/style-guides/blob/master/DVCodingStyle.md)

## 가능한데 드문 경우도 남는다

편의 조건을 제거했다고 모든 코너가 곧바로 나타나는 것은 아니다. 입력이 허용되는지와 실제 선택 분포는 다른 문제다. 단순한 확률 예로 999개 쌍을 독립적으로 균등 선택한다면, 특정 한 쌍을 1,000번 동안 한 번도 못 볼 확률은 `(998/999)^1000`으로 약 36.7%다.

이는 실제 SystemVerilog solver가 쌍마다 균등하게 선택한다는 주장도, 테스트 결과를 측정한 값도 아니다. 입력 공간이 충분히 열려 있어도 유한한 시도만으로 모든 코너를 보장할 수 없다는 설명용 계산이다. 실제 분포는 변수와 제약, 가중치 및 도구의 선택 방식에 따라 확인해야 한다.

그래서 마지막 주소, 최소 길이, 최대 길이 같은 요구를 먼저 적고, 중요한 경계는 directed test나 의도적인 가중치로 확보하는 편이 좋다. 나머지 합법 공간을 랜덤 탐색으로 넓히면 목적이 분명하다. 정렬 전송만 집중하는 테스트는 여전히 유용하지만, 그것을 전체 입력 공간의 대표라고 부르지는 않는다.

다만 모든 편의 조건을 제거하는 것이 목표는 아니다. 특정 DUT가 비정렬 접근을 지원하지 않는다면 정렬 조건은 명세의 일부이며, 이를 풀면 불법 자극이 된다. 먼저 인터페이스의 합법성을 확인하고, 그 범위 안에서 무엇을 테스트 목적상 제한했는지 분리해야 한다.

seed를 늘리기 전에 대표적인 합법 코너가 조건식의 해가 되는지부터 확인하자. 생성이 불가능한 입력은 확률 문제가 아니며, 가능한 입력도 유한한 반복으로 반드시 나오지는 않는다. 이 두 층을 나누면 랜덤 테스트의 성공 로그를 입력 공간에 대한 근거로 더 정확하게 읽을 수 있다.

