핵심 규칙은 단 하나입니다. 모든 피연산자(operand)는 반드시 부호 있는(signed) 값이어야 합니다.
Verilog 언어는 부호 없는(unsigned) 숫자를 기본으로 다루는 경향이 강합니다. 다음 경우에는 모두 부호 없는(unsigned) 값이 만들어집니다:
- 두 피연산자를 사용하는 모든 연산(단, 두 피연산자가 모두 부호 있는(signed) 값인 경우는 제외).
- 명시적으로 진법(base)을 지정한 숫자(예: 12'd10). 단, 's' 수식자(modifier)를 명시적으로 사용한 경우는 제외.
- 비트 선택(bit-select)의 결과.
- 부분 선택(part-select)의 결과.
- 비트 연결(concatenation)의 결과.
결론적으로, $signed 시스템 함수(system function)를 사용하거나, 부호 있는(signed) wire 및 레지스터(register)를 선언하면 됩니다.
예를 들어, 부호 있는(signed) 레지스터와 부호 없는(unsigned) 레지스터를 곱하고, 그 결과를 (당연히) 부호 있는 값으로 취급하려면 다음과 같이 하면 됩니다.
reg [15:0] a; // Unsigned
reg signed [15:0] b;
wire signed [16:0] signed_a;
wire signed [31:0] a_mult_b;
assign signed_a = a; // Convert to signed
assign a_mult_b = signed_a * b
signed_a 는 "a"보다 1 비트 더 넓습니다. 따라서 부호 비트(sign bit)로 쓰일 자리가 하나 더 생기고, 이 자리는 항상 0 입니다. 이 추가 비트가 없었다면, signed_a 에서는 a 의 MSB(most significant bit, 최상위 비트)가 부호 비트로 취급되었을 것입니다.
어쩌면 "a"만 쓰는 대신 {1'b0, a}처럼 해서 signed_a 의 최상위 비트(MSB)를 명시적으로 정해야 한다고 착각할 수도 있습니다. 하지만 Verilog 표준은 어떤 값이 부호 있는(signed) 값인지, 부호 없는(unsigned) 값인지가 오직 수식(expression)만으로 결정된다고 명확히 규정합니다. 따라서 대입문의 좌변(left-hand side)은 이 문제에 아무런 영향을 주지 못합니다. 그래서 "a"는 부호 없는(unsigned) 값으로 취급되고, 0 으로 확장됩니다.