Verilog에서 "연산자"가 의미하는 것
연산자는 신호를 담은 식을 받아 새로운 신호 식을 만듭니다. a + b는 하드웨어입니다 - synthesizer가 그것을 가산기로 만듭니다. a == b는 하드웨어입니다 - 비교기를 만듭니다. 이건 "실행되는 코드"가 아니라 모두 "연산자가 기술하는 회로"입니다.
연산자 메뉴 전체는 외울 만큼 작습니다. 이 문서는 산술, 비교, 논리, 조건 연산자를 다룹니다. Bitwise and Reduction은 직접적인 소프트웨어 대응이 없는 비트 레벨 연산자를 다룹니다.
산술: + - * / %
알아 둘 세 가지.
- 나눗셈은 정수 나눗셈입니다.
7/2는3이지3.5가 아닙니다. Verilog에는 float 타입이 없습니다(엄밀히는real이 있지만 시뮬레이션 전용). - 나눗셈과 modulo는 하드웨어에서 비쌉니다.
/4는 괜찮지만(synthesizer가 right shift로 변환), 런타임 가변n에 대한/n은 여러 사이클짜리 나눗셈기를 만들고 보통은 원하지 않는 결과입니다. - Overflow는 wrap됩니다. N비트 부호 없는 두 값을 더해 N비트를 넘으면 N비트로 잘립니다. carry를 잡고 싶다면 결과를 한 비트 더 넓게 선언하세요.
wire [7:0] a, b;
wire [8:0] sum = a + b; // 9비트 sum이 carry out을 잡음
비교: == != < > <= >=
여섯 비교 연산자 모두 단일 비트 결과를 반환합니다: 참이면 1, 거짓이면 0, 피연산자 중 어느 쪽이든 x나 z 비트가 있으면 x. x/z 케이스를 다루려면 ===와 !==(case-equality 연산자)에 손을 뻗으세요. X and Z Values에서 다룹니다.
여기서 <=는 비교 연산자(less-than-or-equal)입니다. 같은 문자가 procedural block 안에서는 또한 non-blocking assignment(q <= d)를 의미합니다. 문맥으로 구분합니다: 식 안이면 비교이고, 대입되는 값의 왼쪽에 있으면 대입입니다. 겹침이 혼란스럽지만 파서에게는 모호하지 않습니다.
논리: && || !
논리 연산자는 피연산자를 boolean(non-zero는 true, 0은 false)으로 다루고 단일 비트 결과를 만듭니다.
내재화해야 할 핵심 구분: 논리 &&는 비트와이즈 &가 아닙니다.
4'b1100 && 4'b0011 // 1 (둘 다 non-zero, logical AND는 true)
4'b1100 & 4'b0011 // 4'b0000 (양쪽에서 1인 비트 위치가 없음)
||와 |도 마찬가지. if 조건과 ?: 술어에는 logical을, 비트 위치별 AND/OR가 필요할 때는 비트와이즈를 쓰세요.
&&와 ||는 C 의미의 short-circuit입니다: 결과가 왼쪽에서 이미 결정되면 오른쪽이 평가되지 않습니다. 이건 포인터나 함수 호출을 검사하는 testbench에서 의미가 있고, 모든 게 어차피 병렬로 일어나는 synthesis 가능한 RTL에서는 거의 의미가 없습니다.
조건 연산자: ?:
ternary는 mux와 조건 식을 만드는 최고의 친구입니다.
cond ? a : b 패턴은 하드웨어에서 1비트 select의 2-to-1 멀티플렉서입니다. 체인은 3-, 4-way select까지는 괜찮지만, 그 이상은 Case Statement의 case 문이 훨씬 읽기 좋습니다.
?: 연산자는 가끔만 오버라이드하는 기본값을 register에 주는 표준 방법이기도 합니다.
next_value = update ? new_data : next_value;
너비 규칙: 초보자의 함정
산술 연산자의 너비 규칙은 악명 높게 놀랍습니다. 짧은 버전.
- 결과의 너비는 입력 너비들의 최댓값입니다.
- 결과가 더 넓은 곳에 대입되면 zero-extension(부호 있다면 sign-extension)됩니다.
- 중간 계산의 너비도 결과 너비입니다, 즉 중간에서 overflow가 일어납니다.
첫 곱셈은 피연산자 너비가 둘 다 8비트여서 결과 너비도 8비트이고 40000이 들어맞지 않아 overflow합니다. 두 번째는 a를 명시적으로 넓힌 뒤 곱했기에 동작합니다.
수정 라인 기법.
- concatenation 연산자
{8'b0, a}로 zero-extension. $unsigned(a)또는$signed(a)로 해석을 영향.- 의심스러우면 중간 식을 더 넓은 너비로 cast.
연산자 우선순위
표를 외울 필요는 없지만 몇 가지 규칙에 의존하게 됩니다.
*,/,%가+,-보다 강하게 결합.- 비교는 논리(
&&,||)보다 강하게 결합. - 조건 연산자
?:는 매우 낮은 우선순위 - 큰 식 안에서 보통 분기에 괄호가 필요. - 의심스러우면 괄호. 시뮬레이터는 글자 수로 청구하지 않습니다.
out = (mode == 2'd0) ? a + b : a - b; // 괄호로 더 명확
다음에 볼 내용
소프트웨어 사촌처럼 보이는 연산자는 모두 다뤘습니다. 다음 문서 - Bitwise and Reduction - 은 직접적인 소프트웨어 대응이 없는 연산자를 다룹니다: 비트별 AND/OR/XOR과, 전체 vector를 단일 비트로 줄이는 reduction 형태.
자주 묻는 질문
Verilog는 어떤 연산자를 지원하나요?
Verilog에는 네 가지 큰 연산자 가족이 있습니다: 산술(+, -, *, /, %), 비교(==, !=, <, >, <=, >=), 논리(&&, ||, !), 그리고 비트와이즈/reduction(&, |, ^, ~, ~&, ~|, ~^). 거기에 shift 연산자(<<, >>, <<<, >>>), concatenation {}, replication {N{...}}, 그리고 조건 연산자 ?:가 있습니다.
Verilog에서 &&와 &의 차이는?
&&는 논리 AND - 각 피연산자를 boolean(0 또는 non-zero)으로 다루고 1비트 결과를 반환합니다. &는 비트와이즈 AND - 비트를 위치별로 짝짓습니다. 4'b1100 && 4'b0011은 1(둘 다 non-zero)이고, 4'b1100 & 4'b0011은 4'b0000입니다. 조건에는 &&, 비트 레벨 연산에는 &.
Verilog에서 나눗셈은 어떻게 동작하나요?
정수 나눗셈입니다 - 소수 부분이 버려집니다. 7 / 2는 3이지 3.5가 아닙니다. % 연산자는 나머지를 줍니다: 7 % 2는 1입니다. 0으로 나누면 시뮬레이션에서 x(unknown)가 됩니다. 두 연산자 모두 기술적으로는 synthesis 가능하지만 FPGA와 ASIC에서 매우 크고 느린 하드웨어를 만들어 냅니다 - 제수가 2의 거듭제곱이 아니라면 synthesis 가능한 경로에서 피하세요.
Verilog의 조건 연산자란?
?:는 C에서 가져온 ternary 또는 조건 연산자입니다. cond ? a : b는 cond가 true(non-zero)이면 a로, 아니면 b로 평가됩니다. mux와 비슷한 로직에 가장 많이 쓰는 구문입니다: out = sel ? in1 : in0는 2-to-1 mux를 만듭니다. ?: 체인은 더 큰 mux를 만들지만 두 입력을 넘어서면 보통 case가 더 명확합니다.