---
title: "출력은 16비트인데 덧셈기는 7비트로 줄어드는 이유"
author: "브레이브브라우저쓰자"
published_at: "2026-10-21T07:40:03.727Z"
updated_at: "2026-10-06T01:25:45.139Z"
tags: ["bit-width reduction"]
canonical_url: "https://ariser.io/@writer_a9817d5a8de0/%EC%B6%9C%EB%A0%A5%EC%9D%80-16%EB%B9%84%ED%8A%B8%EC%9D%B8%EB%8D%B0-%EB%8D%A7%EC%85%88%EA%B8%B0%EB%8A%94-7%EB%B9%84%ED%8A%B8%EB%A1%9C-%EC%A4%84%EC%96%B4%EB%93%9C%EB%8A%94-%EC%9D%B4%EC%9C%A0"
ai_assisted: true
---

# 출력은 16비트인데 덧셈기는 7비트로 줄어드는 이유

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

[원문](https://ariser.io/@writer_a9817d5a8de0/%EC%B6%9C%EB%A0%A5%EC%9D%80-16%EB%B9%84%ED%8A%B8%EC%9D%B8%EB%8D%B0-%EB%8D%A7%EC%85%88%EA%B8%B0%EB%8A%94-7%EB%B9%84%ED%8A%B8%EB%A1%9C-%EC%A4%84%EC%96%B4%EB%93%9C%EB%8A%94-%EC%9D%B4%EC%9C%A0)

16비트 출력에 연결한 덧셈기가 합성 후 훨씬 좁아졌다. 출력을 줄이지 않았는데 어떻게 계산을 줄일 수 있을까? bit-width reduction은 결과를 대충 근사하는 작업이 아니다. **상위 비트가 항상 정해져 있거나 관측 결과에 필요하지 않다는 근거를 찾아, 같은 결과를 더 작은 연산으로 표현하는 작업**이다.

## 넓게 적은 식에도 실제 값의 범위가 있다

부호 없는 6비트 입력 a와 b를 더해 16비트 출력 sum으로 내보낸다고 하자. 입력을 각각 16비트로 0 확장한 뒤 더하면 표현상의 덧셈 폭은 넓다.

```systemverilog
wire [15:0] a16 = {10'b0, a};
wire [15:0] b16 = {10'b0, b};
assign sum = a16 + b16;
```

a와 b의 최대값은 63이다. 합은 0부터 126까지이므로 7비트면 정확히 담을 수 있고, 16비트 결과의 상위 9비트는 항상 0이다. 같은 계산을 먼저 7비트로 수행하고 그 결과를 0 확장해도 된다.

```systemverilog
wire [6:0] sum7 = {1'b0, a} + {1'b0, b};
assign sum = {9'b0, sum7};
```

두 입력 64가지씩, 총 4,096조합에서 두 표현의 결과를 비교할 수 있다. 어떤 입력에서도 합이 127을 넘지 않으므로 7비트 표현은 정보를 버리지 않는다. 출력 sum이 여전히 16비트라는 사실과 내부 덧셈에 16비트 모두가 필요하다는 주장은 다르다.

Yosys의 wreduce 공식 설명도 연산의 단어 폭을 줄이는 역할을 제시한다. 구현은 부호 없는 입력의 상위 0이나 부호 확장으로 반복된 비트, 사용되지 않는 출력 비트 등을 구분해서 처리한다. 이 예처럼 알려진 0을 확장한 표현과, 사람이 테스트에서 우연히 작은 값만 보았던 표현은 같은 근거가 아니다. [wreduce의 공식 설명](https://yosyshq.readthedocs.io/projects/yosys/en/stable/cmd/index_passes_opt.html#wreduce-reduce-the-word-size-of-operations-if-possible), [폭과 부호를 처리하는 구현](https://github.com/YosysHQ/yosys/blob/main/passes/opt/wreduce.cc)

## 입력 폭과 결과 폭을 같게 줄이면 틀린다

6비트 입력이라는 이유로 덧셈 결과도 6비트만 남기면 carry를 잃는다. a=b=63일 때 정확한 합은 126, 즉 7비트의 1111110이다. 낮은 6비트만 남긴 결과는 62다. 이를 다시 16비트로 0 확장해도 이미 잃어버린 최상위 비트를 복구할 수는 없다.

오류는 최대값 하나에만 나타나지 않는다. a+b가 64 이상인 조합은 2,016개다. 이 조합들은 정확한 16비트 합이 필요한 계약에서 6비트 결과로 바꾸면 모두 달라진다. 4,096조합의 거의 절반이므로 작은 값 몇 개만 테스트해서 좁혀도 된다고 판단하기 어렵다. 이 경우의 수는 가상 입력 공간을 전수 계산한 값이다.

반대로 실제 출력 계약이 처음부터 합의 낮은 6비트만 내보내는 것이라면, 모듈로 64 결과만 보존하면 된다. 같은 carry가 그 관측 결과에는 필요하지 않다. 다만 carry를 별도 출력하거나, 다음 비교에서 전체 합을 사용한다면 다시 필요해진다. **줄일 수 있는 폭은 입력 크기만으로 정해지지 않고, 어떤 결과 비트를 관측하는지에도 달려 있다.**

## 부호 비트를 제거하는 것과 0을 제거하는 것은 다르다

입력을 signed 6비트로 바꾸면 범위는 −32부터 31이다. 두 값의 합은 −64부터 62여서 여전히 7비트 signed 값으로 표현할 수 있다. 그러나 결과를 16비트로 넓힐 때는 0이 아니라 부호를 확장해야 한다.

예를 들어 −32와 −32의 합은 −64다. 7비트 표현은 1000000이고, 16비트에서는 0xFFC0이어야 한다. 같은 7비트 패턴을 0 확장하면 0x0040, 즉 +64가 된다. 폭을 충분히 확보했더라도 확장 의미를 바꾸면 결과는 틀린다.

이를 구현할 때는 피연산자의 signed 선언과 식의 크기 규칙을 확인하고, 7비트 결과의 부호 비트를 위쪽에 복제해야 한다. 상위 비트가 같은 부호 비트의 반복이라서 제거 가능한 경우와, 항상 0이라서 제거 가능한 경우를 구별해야 한다. 시프트나 비교에 사용되는 값이라면 해당 연산이 부호와 폭을 어떻게 해석하는지도 확인한다.

폭 감소의 근거는 RTL과 중간 표현에서 드러나는 상수·연결·관측 관계여야 한다. “리셋 뒤 보통 이 값 이하로 움직인다”는 테스트 경험을 그대로 합성기의 증명 능력으로 간주할 수 없다. 순차 회로의 도달 범위에 의존해 수동으로 줄인다면 그 범위가 유지된다는 별도 검증과 초기·리셋 조건이 필요하다. wreduce의 옵션 중에는 don't-care 최적화나 메모리 주소 폭에 관한 설정도 있으므로, 폭 감소를 확인한 흐름의 조건을 함께 읽는다.

좁아진 연산기를 보고 의심이 든다면 최대·최소값과 관측 비트를 먼저 적어 보면 된다. 필요한 carry와 부호가 모두 보존되는지, 상위 출력은 올바른 상수 또는 확장으로 복원되는지 확인한다. 그 관계가 맞으면 넓은 출력 포트를 유지하면서도 내부 계산을 줄일 수 있고, 그 근거가 없으면 폭 감소는 정확한 최적화가 아니라 기능 변경이 된다.

