두 개의 작지만 값어치 하는 연산자
Verilog에는 두 가지 {} 모양이 있습니다.
- Concatenation -
{a, b, c}- 여러 신호를 더 넓은 하나로 붙입니다. - Replication -
{N{pattern}}- 패턴을 N번 복제합니다.
둘 다 끊임없이 쓰게 됩니다. bus를 쪼개고, 잇고, 패딩하고, sign-extension할 때마다 이 두 연산자 중 하나가 답입니다.
Concatenation: {a, b, c}
가장 단순한 경우: 두 신호를 하나로 쌓기.
왼쪽에서 오른쪽으로 읽기: a가 상위 절반, b가 하위 절반. {} 안의 첫 피연산자가 최상위입니다. 결과 너비는 피연산자 너비의 합입니다.
피연산자 개수는 제한이 없습니다.
wire [31:0] word = {byte3, byte2, byte1, byte0};
피연산자 너비가 달라도 됩니다.
wire [11:0] frame = {start_bit, data_byte, parity, stop_bit};
// 1비트 8비트 1비트 2비트 = 12
흔한 규칙: concatenation의 모든 피연산자는 명시적 너비를 가져야 합니다. 크기 없는 literal(1'b1 대신 그냥 1)은 파서가 몇 비트를 할당할지 몰라 오류가 됩니다. {} 안에서는 항상 1'b0, 1'b1, 4'd0로 적고 맨 0이나 1은 쓰지 마세요.
좌변에서의 Concatenation
대입의 LHS에 있는 concatenation은 넓은 신호를 부분으로 분리 합니다.
가산기와 carry의 정석 패턴입니다. {carry_out, sum_bits}는 대입 좌변에 있는 하나의 9비트 목적지이고, 비트가 분배됩니다: 최상위 비트가 carry_out, 하위 8비트가 sum_bits.
LHS concatenation은 assign과 procedural block에서 모두 동작합니다.
always @(posedge clk) begin
{high_byte, low_byte} <= incoming_word;
end
Replication: {N{pattern}}
replication 연산자는 패턴을 고정된 횟수만큼 복제합니다. 모양은 {N{pattern}} - 개수, 그다음 자체 중괄호 쌍 안의 패턴.
N은 상수여야 합니다 - 컴파일러는 elaboration 시점에 결과 너비를 알아야 합니다. 패턴은 literal, parameter, 또는 너비를 알 수 있는 어떤 식이든 됩니다.
내부 중괄호를 잊지 마세요. {8 1'b1}은 syntax error이고, {8{1'b1}}이 맞습니다. 바깥 {}가 연산자이고, 안의 {...}가 복제될 패턴을 감쌉니다.
둘 결합: Sign과 Zero Extension
두 연산자는 자연스럽게 결합해 더 넓은 값을 만듭니다.
{ {8{a_negative[7]}}, a_negative }는 표준 sign-extension 패턴입니다. 읽으면: 부호 비트를 여덟 번 복제하고 그 뒤에 원본 8비트를 붙임. 순 결과: 같은 숫자의 16비트 two's-complement 표현.
부호 없는 확장은 대입에 맡길 수 있습니다 - 대상이 더 넓으면 Verilog이 자동으로 zero-extension합니다.
wire [15:0] zext_auto = a_unsigned; // 동작, 상위 8비트는 0
하지만 sign-extension은 피연산자와 대상이 둘 다 signed로 선언되지 않는 한 결코 암시적으로 일어나지 않습니다. 명시적 replication idiom이 더 안전합니다.
유용한 패턴
N개의 1로 된 mask 만들기
parameter N = 5;
wire [31:0] mask = { {32-N{1'b0}}, {N{1'b1}} };
// 예. N=5일 때 mask = 32'h0000_001F
vector 뒤집기
Verilog에는 내장 reverse가 없지만, concatenation으로 인라인으로 작성할 수 있습니다.
wire [3:0] forward = 4'b1010;
wire [3:0] reversed = {forward[0], forward[1], forward[2], forward[3]};
// reversed = 4'b0101
더 넓은 vector라면 generate 루프나 function이 깔끔합니다.
flag를 상태 바이트로 묶기
wire [7:0] status = {
error_flag, // [7]
overflow, // [6]
underflow, // [5]
ready, // [4]
busy, // [3]
1'b0, // [2] 예약
1'b0, // [1] 예약
valid // [0]
};
1비트 예약 슬롯은 명시적 너비를 가집니다 - {} 안에서 맨 0은 안 됩니다.
흔한 실수
{} 안의 unsized literal. {a, 0}은 syntax error이거나 32비트 넓은 0이 됩니다. 항상 sizing: {a, 1'b0}.
replication의 안쪽 중괄호를 잊는 것. {8 1'b1}은 파싱 안 됨; {8{1'b1}}은 됨.
순서 혼동. {a, b}는 a를 상위에, b를 하위에 둡니다. 가정을 뒤집으면 어디선가 바이트 순서가 뒤집힌 결과를 보게 됩니다.
0번 replication. {0{...}}은 표준 Verilog에서 불법입니다. SystemVerilog은 허용하고(너비 0 결과 생성). 일반 Verilog은 거부합니다.
다음에 볼 내용
이제 Verilog의 모든 연산자를 봤습니다. 다음 장은 기어를 바꿔 구조로 들어갑니다 - 모듈이 서로 어떻게 연결되는지, 포트 규칙, 그리고 서브모듈을 인스턴스화해 더 큰 설계를 만드는 문법.
자주 묻는 질문
Verilog에서 신호는 어떻게 concatenate하나요?
중괄호를 사용합니다: {a, b, c}는 피연산자를 왼쪽에서 오른쪽으로 붙여 하나의 넓은 vector를 만듭니다. a의 MSB가 결과의 MSB가 되고, c의 LSB가 결과의 LSB가 됩니다. 결과의 너비는 피연산자 너비의 합입니다. concatenation은 대입의 오른쪽(값 구성용)과 왼쪽(값 분리용) 모두에서 동작합니다.
Verilog에서 {N{pattern}}은 무엇을 의미하나요?
replication 연산자입니다: pattern의 N개 사본을 concatenate해서 만듭니다. {8{1'b1}}은 8비트 전부 1 값(8'hFF)입니다. {4{2'b10}}은 8비트 값 8'b10101010입니다. replication은 손으로 쓰지 않고도 zero-extension, sign-extension, 또는 어떤 반복 비트 패턴이든 만드는 방법입니다.
Verilog에서 신호를 sign-extension하려면?
replication으로 부호 비트를 반복합니다: { {24{a[7]}}, a }는 비트 7(부호 비트)을 24번 복제한 뒤 원본을 붙여 8비트 a를 32비트로 확장합니다. 부호 없는 zero-extension은 1'b0을 복제하거나, 대상이 더 넓을 때 대입이 암시적으로 처리하도록 두면 됩니다.
대입 좌변에서 concatenation을 쓸 수 있나요?
네 - 하나의 넓은 소스에서 여러 타겟에 대입하는 방법입니다. {carry, sum} = a + b;는 한 문장으로 덧셈 결과를 carry(상위 비트)와 sum(나머지)에 넣습니다. 각 타겟은 자기 너비를 유지하고, 파서가 우변 비트를 그에 맞춰 분배합니다.