2-2. Verilog 연산자
1. Verilog 연산자 개요
Verilog는 디지털 회로를 모델링하고 시뮬레이션하기 위한 하드웨어 기술 언어(HDL)입니다. Verilog에서 연산자는 회로의 동작을 정의하는 데 핵심적인 역할을 합니다. 이러한 연산자들은 다양한 데이터 타입에 적용되어 덧셈, 뺄셈, 논리 연산, 비트 단위 연산 등 다양한 기능을 수행합니다. 본 문서에서는 Verilog에서 제공하는 연산자들을 종류별로 자세히 살펴보고, 예제를 통해 실제 사용 방법을 익혀보겠습니다.
2. 연산자 종류
Verilog는 다양한 연산을 수행하기 위한 여러 종류의 연산자를 제공합니다. 각 연산자는 우선순위와 결합 법칙을 가지며, 이를 통해 연산의 순서가 결정됩니다. 주요 연산자 종류는 다음과 같습니다.
- 산술 연산자
- 논리 연산자
- 비트 단위 연산자
- 관계 연산자
- 축소 연산자
- 시프트 연산자
- 조건 연산자
- 연접 연산자
각 연산자에 대해 자세히 알아보겠습니다.
1) 산술 연산자
산술 연산자는 덧셈, 뺄셈, 곱셈, 나눗셈, 나머지 연산을 수행합니다.
| 연산자 | 설명 | 예시 |
|---|---|---|
+ |
덧셈 | a + b |
- |
뺄셈 | a - b |
* |
곱셈 | a * b |
/ |
나눗셈 | a / b |
% |
나머지 | a % b |
+,-,*연산은 부호 있는(signed) 또는 부호 없는(unsigned) 피연산자에 대해 모두 지원됩니다./연산에서 피연산자가 모두 정수형이고 나누어떨어지지 않으면 소수점 이하는 버려집니다.%연산자는 나머지 연산을 수행하며, 나눗셈과 동일한 부호 규칙을 따릅니다.
2) 논리 연산자
논리 연산자는 true 또는 false 값을 반환하며, 조건식을 평가하는 데 사용됩니다.
| 연산자 | 설명 | 예시 |
|---|---|---|
&& |
논리 AND | a && b |
|| |
논리 OR | a || b |
! |
논리 NOT | !a |
&&연산자는 두 피연산자가 모두true일 때true를 반환합니다.||연산자는 두 피연산자 중 하나라도true이면true를 반환합니다.!연산자는 피연산자가true이면false를,false이면true를 반환합니다.
3) 비트 단위 연산자
비트 단위 연산자는 각 비트에 대해 개별적으로 연산을 수행합니다.
| 연산자 | 설명 | 예시 |
|---|---|---|
~ |
비트 NOT | ~a |
& |
비트 AND | a & b |
| |
비트 OR | a | b |
^ |
비트 XOR | a ^ b |
^~, ~^ |
비트 XNOR | a ^~ b, ~^ b |
~연산자는 각 비트를 반전시킵니다.&연산자는 두 피연산자의 각 비트에 대해 AND 연산을 수행합니다.|연산자는 두 피연산자의 각 비트에 대해 OR 연산을 수행합니다.^연산자는 두 피연산자의 각 비트에 대해 XOR 연산을 수행합니다.^~,~^연산자는 두 피연산자의 각 비트에 대해 XNOR 연산을 수행합니다.
4) 관계 연산자
관계 연산자는 두 피연산자의 크기를 비교합니다.
| 연산자 | 설명 | 예시 |
|---|---|---|
> |
큼 | a > b |
< |
작음 | a < b |
>= |
큼 또는 같음 | a >= b |
<= |
작음 또는 같음 | a <= b |
<mark class="highlight"> |
같음 | a </mark> b |
!<mark class="highlight"><strong><u> |
같지 않음 | a !</u></strong></mark> b |
- 관계 연산자는
true또는false값을 반환합니다. ==와!=연산자는 두 피연산자의 모든 비트가 같은지 또는 다른지를 비교합니다.
5) 축소 연산자
축소 연산자는 단항 연산자로서, 피연산자의 모든 비트에 대해 연산을 수행하여 하나의 비트 결과를 생성합니다.
| 연산자 | 설명 | 예시 |
|---|---|---|
& |
축소 AND | &a |
| |
축소 OR | |a |
^ |
축소 XOR | ^a |
~& |
축소 NAND | ~&a |
~| |
축소 NOR | ~|a |
~^, ^~ |
축소 XNOR | ~^a, ^~a |
- 예를 들어,
&a는a의 모든 비트에 대해 AND 연산을 수행합니다. a가 4비트인 경우,&a는a[3] & a[2] & a[1] & a[0]과 같습니다.
6) 시프트 연산자
시프트 연산자는 비트 열을 왼쪽 또는 오른쪽으로 이동시킵니다.
| 연산자 | 설명 | 예시 |
|---|---|---|
<< |
왼쪽 시프트 | a << b |
>> |
오른쪽 시프트 | a >> b |
<<< |
왼쪽 산술 시프트 | a <<< b |
>>> |
오른쪽 산술 시프트 | a >>> b |
<<연산자는a를b비트만큼 왼쪽으로 이동시킵니다. 빈 비트는 0으로 채워집니다.>>연산자는a를b비트만큼 오른쪽으로 이동시킵니다. 빈 비트는 0으로 채워집니다 (unsigned인 경우). signed인 경우 최상위 비트(MSB)로 채워집니다.<<<는 왼쪽 산술 시프트,>>>는 오른쪽 산술 시프트입니다. signed, unsigned에 따라 채워지는 비트가 다릅니다.
7) 조건 연산자
조건 연산자는 삼항 연산자이며, 조건에 따라 두 개의 값 중 하나를 선택합니다.
| 연산자 | 설명 | 예시 |
|---|---|---|
?: |
조건 연산자 (ternary operator) | condition ? value1 : value2 |
condition이true이면value1을 반환하고,false이면value2를 반환합니다.- 조건 연산자는
if-else문과 유사한 기능을 제공하지만, 더 간결하게 표현할 수 있습니다.
8) 연접 연산자
연접 연산자는 여러 개의 신호를 묶어 하나의 신호로 만듭니다.
| 연산자 | 설명 | 예시 |
|---|---|---|
{} |
연접 (concatenation) | {a, b, c} |
- 예를 들어,
{a, b, c}는 신호a,b,c를 순서대로 연결하여 하나의 신호를 생성합니다.
3. 연산자 우선순위
Verilog 연산자는 각기 다른 우선순위를 가집니다. 연산자 우선순위는 연산의 순서를 결정하며, 괄호를 사용하여 명시적으로 우선순위를 지정할 수 있습니다. 일반적으로 괄호는 연산의 의도를 명확하게 하고, 예상치 못한 결과를 방지하는 데 도움이 됩니다.
다음은 Verilog 연산자의 우선순위를 나타낸 표입니다 (높은 우선순위에서 낮은 우선순위 순).
| 연산자 | 설명 | 우선순위 |
|---|---|---|
() |
괄호 (가장 높은 우선순위) | 1 |
. |
멤버 접근 | 1 |
[] |
배열/비트 선택 | 1 |
+ - ! ~ & ~ & | ~| ^ ~^ |
단항 연산자 (부호, NOT, 비트 NOT, 축소 연산자) | 2 |
* / % |
산술 연산 (곱셈, 나눗셈, 나머지) | 3 |
+ - |
산술 연산 (덧셈, 뺄셈) | 4 |
<< >> <<< >>> |
시프트 연산 | 5 |
< <= > >= |
관계 연산 | 6 |
== !<mark class="highlight"><strong><u> </u></strong></mark><mark class="highlight"> !</mark> |
동일성 연산 | 7 |
& |
비트 AND | 8 |
^ ~^ ~^ |
비트 XOR, XNOR | 9 |
| |
비트 OR | 10 |
&& |
논리 AND | 11 |
|| |
논리 OR | 12 |
?: |
조건 연산 | 13 |
{} {} |
연접, 반복 연접 | 14 |
4. 연산자 사용 예제
다음은 다양한 연산자를 사용하는 간단한 Verilog 예제입니다.
module operator_example;
// 데이터 타입 선언
reg [3:0] a, b, result;
reg [7:0] c;
reg flag;
// 초기값 설정
initial begin
a = 4'b1010; // 10
b = 4'b0101; // 5
c = 8'b11001100; // 204
end
// 산술 연산자 예제
always @(*) begin
result <mark class="highlight"><strong><u> a + b; // 10 + 5 </u></strong></mark> 15
$display("산술 연산: a + b = %d", result);
result <mark class="highlight"><strong><u> a - b; // 10 - 5 </u></strong></mark> 5
$display("산술 연산: a - b = %d", result);
result <mark class="highlight"><strong><u> a * b; // 10 * 5 </u></strong></mark> 50
$display("산술 연산: a * b = %d", result);
result <mark class="highlight"><strong><u> a / b; // 10 / 5 </u></strong></mark> 2
$display("산술 연산: a / b = %d", result);
result <mark class="highlight"><strong><u> a % b; // 10 % 5 </u></strong></mark> 0
$display("산술 연산: a %% b = %d", result);
end
// 논리 연산자 예제
always @(*) begin
flag = (a > 0) && (b < 10);
$display("논리 연산: (a > 0) && (b < 10) = %b", flag);
flag = (a > 10) || (b < 10);
$display("논리 연산: (a > 10) || (b < 10) = %b", flag);
flag = !(a > b);
$display("논리 연산: !(a > b) = %b", flag);
end
// 비트 단위 연산자 예제
always @(*) begin
result = ~a;
$display("비트 연산: ~a = %b", result);
result = a & b;
$display("비트 연산: a & b = %b", result);
result = a | b;
$display("비트 연산: a | b = %b", result);
result = a ^ b;
$display("비트 연산: a ^ b = %b", result);
end
// 관계 연산자 예제
always @(*) begin
flag = (a > b);
$display("관계 연산: a > b = %b", flag);
flag = (a <mark class="highlight"> b);
$display("관계 연산: a </mark> b = %b", flag);
flag <mark class="highlight"><strong><u> (a !</u></strong></mark> b);
$display("관계 연산: a !<mark class="highlight"><strong><u> b </u></strong></mark> %b", flag);
end
// 축소 연산자 예제
always @(*) begin
result = &a; // a의 모든 비트가 1이면 1, 아니면 0
$display("축소 연산: &a = %b", result);
result = |a; // a의 비트 중 하나라도 1이면 1, 아니면 0
$display("축소 연산: |a = %b", result);
result = ^a; // a의 비트가 짝수 개의 1이면 0, 홀수 개의 1이면 1
$display("축소 연산: ^a = %b", result);
end
// 시프트 연산자 예제
always @(*) begin
result = a << 1;
$display("시프트 연산: a << 1 = %b", result);
result = c >> 2;
$display("시프트 연산: c >> 2 = %b", result);
end
// 조건 연산자 예제
always @(*) begin
result = (a > b) ? a : b;
$display("조건 연산: (a > b) ? a : b = %d", result);
end
// 연접 연산자 예제
always @(*) begin
result = {a[3:2], b[1:0]};
$display("연접 연산: {a[3:2], b[1:0]} = %b", result);
end
endmodule
이 예제에서는 각 연산자를 사용하여 다양한 연산을 수행하고, $display 문을 통해 결과를 출력합니다. 이를 통해 각 연산자의 동작을 확인하고 이해할 수 있습니다.
5. 중요 팁과 주의사항
1) 데이터 타입의 중요성
Verilog 연산에서 데이터 타입은 매우 중요합니다. 부호 있는(signed) 데이터 타입과 부호 없는(unsigned) 데이터 타입은 연산 결과에 큰 영향을 미칠 수 있습니다. 예를 들어, 부호 없는 숫자를 음수와 연산하면 예기치 않은 결과를 얻을 수 있습니다.
reg signed [3:0] signed_a = -5; // 부호 있는 정수
reg [3:0] unsigned_b = 3; // 부호 없는 정수
always @(*) begin
$display("signed_a + unsigned_b = %d", signed_a + unsigned_b); // -2
end
2) 우선순위와 괄호 사용
연산자 우선순위를 정확히 이해하고 괄호를 사용하여 연산의 순서를 명확하게 지정하는 것이 중요합니다. 괄호는 코드의 가독성을 높이고, 예상치 못한 결과를 방지하는 데 도움이 됩니다. 특히 복잡한 표현식에서는 괄호를 적극적으로 사용하여 의도를 명확히 하는 것이 좋습니다.
3) 비트 폭 (Bit Width)
연산 결과의 비트 폭은 피연산자의 비트 폭에 따라 결정됩니다. 연산 결과를 저장할 변수의 비트 폭이 충분하지 않으면, 데이터 손실이 발생할 수 있습니다.
reg [3:0] a = 8; // 1000
reg [3:0] b = 7; // 0111
reg [3:0] result;
always @(*) begin
result = a + b; // 15 (1111) -> 결과는 1111 이지만, result는 4비트이므로 오버플로우가 발생하지 않음
$display("a + b = %d", result); // result = 15
result = a * b; // 56 (111000) -> 6비트 필요. 하지만 result는 4비트이므로 하위 4비트만 저장됨
$display("a * b = %d", result); // result = 8
end
4) 시프트 연산의 주의
시프트 연산은 비트 열을 이동시키므로, 데이터 손실이 발생할 수 있습니다. 또한, 부호 있는 숫자를 오른쪽으로 시프트할 때, 산술 시프트와 논리 시프트의 동작이 다르므로 주의해야 합니다.
5) X, Z 값 처리
Verilog 시뮬레이션에서 X와 Z 값은 초기화되지 않은 상태를 나타냅니다. 연산에 이러한 값이 포함되면, 결과도 X 또는 Z가 될 수 있습니다. 따라서, 연산 전에 변수를 적절하게 초기화하는 것이 중요합니다.
6. 결론
Verilog 연산자는 디지털 회로를 모델링하고 설계하는 데 필수적인 요소입니다. 다양한 연산자를 이해하고 적절하게 활용하면, 복잡한 기능을 구현하는 회로를 효과적으로 설계할 수 있습니다. 데이터 타입, 연산자 우선순위, 비트 폭, 그리고 시프트 연산과 관련된 주의사항을 숙지하여, 더욱 정확하고 효율적인 Verilog 코드를 작성할 수 있습니다. 본 문서에서 제공된 예제를 통해 각 연산자의 동작을 이해하고, 실제 설계에 적용해 보시기 바랍니다.
비슷한 글 추천
3-1. Verilog의 구문 (Statement) - if-else 구문
Verilog의 제어 흐름 구문인 if-else 문을 설명하고, 조건에 따른 동작 제어 방법을 익힙니다. 예제와 함께 실습합니다.
2-3. Verilog의 모듈과 인스턴스
모듈 정의, 포트 연결, 모듈 인스턴스화 방법을 설명합니다. 계층적 설계를 위한 핵심 개념을 다룹니다.
3-2. Verilog의 구문 (Statement) - case 구문
Verilog의 case 문을 설명하고, 다양한 조건을 처리하는 방법을 배웁니다. 예제를 통해 case 문의 활용법을 익힙니다.
3-3. Verilog의 구문 (Statement) - for, while, repeat 구문
Verilog의 반복 구문인 for, while, repeat 문을 설명하고, 반복적인 작업을 효율적으로 처리하는 방법을 익힙니다.
Comments (0)
No comments yet. Be the first to comment!
Please to write a comment.