2 / 24 · 개념
비트 폭, 부호 확장과 오버플로
같은 비트열의 다른 의미와 축소 위치를 수치 예제로 확인합니다.
내용은 무료로 볼 수 있습니다. 수강 신청하면 학습 기록을 저장할 수 있어요.
비트열과 숫자를 구분하기
8비트 1111_1101은 unsigned로 253, 2의 보수 signed로 -3입니다. 저장된 비트는 같지만 비교, 확장, 나눗셈의 의미가 다릅니다. 8비트 signed 범위는 -128~127이고 unsigned 범위는 0~255입니다. 폭은 표현 가능한 값의 개수를 결정하고 부호는 그 값을 배치하는 방법을 결정합니다. 따라서 인터페이스에 단순히 '8비트'만 적으면 숫자 계약이 완성되지 않습니다.
unsigned 253을 16비트로 옮길 때는 앞에 0을 채웁니다. signed -3을 옮길 때는 원래 최상위 비트 1을 복제하여 1111_1111_1111_1101로 만듭니다. 이를 부호 확장이라고 합니다. -3을 0으로 확장하면 253이 되어 원래 값을 보존하지 못합니다. SystemVerilog에서는 연결 연산의 결과와 부분 선택이 원래 signed 선언의 의도를 그대로 유지한다고 가정하지 말고, 계산 전에 폭과 타입을 명시적으로 맞춥니다.
logic [7:0] ua, ub;
logic [8:0] usum;
logic signed [7:0] sa, sb;
logic signed [8:0] sax, sbx, ssum;
assign usum = {1'b0, ua} + {1'b0, ub};
assign sax = {sa[7], sa};
assign sbx = {sb[7], sb};
assign ssum = sax + sbx;이 예시는 더하기 전에 두 입력을 9비트로 확장합니다. unsigned의 255+1은 9비트로 256이며 하위 8비트는 0입니다. signed의 127+1도 수학적으로 128이지만 signed 8비트로 줄이면 -128로 읽힙니다. carry는 unsigned의 범위를 넘었는지, signed overflow는 signed 범위를 넘었는지를 나타냅니다. 같은 부호 두 수를 더했는데 결과 부호가 바뀌면 signed overflow입니다. -1+1=0에서는 carry가 생겨도 signed overflow는 없습니다.
곱셈에서는 폭 계획을 더 일찍 해야 합니다. unsigned 8비트 두 수의 최대 곱은 255×255=65025이므로 16비트면 충분합니다. 네 개의 8비트 unsigned 값을 더한 최대 합은 1020이므로 10비트가 필요합니다. 항마다 8비트로 잘라 더하면 각 중간 carry가 사라져 마지막에 폭을 키워도 복구할 수 없습니다. 결과 포트가 넓다고 모든 중간 표현식이 자동으로 원하는 수학적 폭이 된다고 믿지 말고 확장과 축소 지점을 코드에 드러냅니다.
| 연산 | 넓은 결과 | 8비트로 축소한 해석 |
|---|---|---|
| unsigned 255+1 | 256 | 0, carry=1 |
| signed 127+1 | 128 | -128, overflow=1 |
| signed -3+2 | -1 | -1, overflow=0 |
경고를 끄기 전에 의도한 버림인지 확인합니다. Verilator의 WIDTH 계열 경고 설명은 크기가 맞지 않는 표현식과 대입을 찾는 참고 자료입니다. 여기서 제시한 코드는 폭 의도를 설명하는 RTL이며 본 과정의 Node 검증은 숫자 모델을 실행합니다. 실제 HDL 도구에서 컴파일한 사실을 이 숫자 검증으로 대신하지 않습니다. 경계값 0, 최대값, 최소값과 부호가 다른 조합을 따로 시험해야 일반적인 양수 예제에서 숨은 오류를 찾을 수 있습니다.
직접 생각해 보기
8비트 signed -3과 2를 9비트로 확장해 더한 결과를 구하세요. 8비트 unsigned 네 값 255,255,255,255를 정확히 더하는 데 필요한 최소 폭도 구하세요.
해설 보기
-3은 9비트 111111101, 2는 000000010이며 합은 111111111, 즉 -1입니다. 네 값의 합은 1020입니다. 9비트 최대값은 511, 10비트 최대값은 1023이므로 최소 10비트입니다.