[Verilog 문법] 3.4 비트 조작

YUN·2026년 1월 23일

디지털 회로 설계

목록 보기
13/20

비트 조작

데이터를 비트 단위로 조작하는 것

비트 슬라이싱

(1) 고정 인덱스 슬라이싱

wire [31:0] data = 32'hDEADBEEF;

// 고정 범위 선택
wire [7:0]  byte0 = data[7:0];     // EF
wire [7:0]  byte1 = data[15:8];    // BE
wire [7:0]  byte2 = data[23:16];   // AD
wire [7:0]  byte3 = data[31:24];   // DE

// 단일 비트 선택
wire        lsb   = data[0];       // 1 (최하위 비트)
wire        msb   = data[31];      // 1 (최상위 비트)

위와 같이 벡터에서 원하는 비트의 데이터만 추출할 수 있다.

(2) 가변 인덱스 슬라이싱

wire [31:0] data;
reg  [1:0]  sel

// 방법 1: +: 연산자 (권장)
wire [7:0] byte_sel = data[sel*8 +: 8];  // sel 위치부터 8비트

// 방법 2: -: 연산자
wire [7:0] byte_sel2 = data[sel*8+7 -: 8];  // sel*8+7부터 아래로 8비트

위와 같이 +:-:를 이용하여 가변적인 인덱스로 슬라이싱할 수 있다.

data[base +: width]
  • +: -> base부터 위로 width 비트
  • -: -> base부터 아래로 width 비트

비트 연결 (Concatenation)

Concatenation 연산 ({}) 을 활용하여 비트를 연결할 수(합칠 수) 있다

(1) 예시

wire [7:0]  a = 8'hDE;
wire [7:0]  b = 8'hAD;
wire [7:0]  c = 8'hBE;
wire [7:0]  d = 8'hEF;

// 연결: 왼쪽이 MSB, 오른쪽이 LSB
wire [31:0] combined = {a, b, c, d};  // 32'hDEADBEEF

// 다양한 크기 연결
wire [15:0] half = {a, b};            // 16'hDEAD
wire [11:0] mixed = {a[3:0], d};      // 12'hEEF

이런식으로 Concatenation 연산 ({}) 을 활용하여 비트를 연결할 수(합칠 수) 있다.

// 필드 결합 (패킷 헤더 등)
wire [3:0]  version = 4'h4;
wire [3:0]  ihl     = 4'h5;
wire [7:0]  tos     = 8'h00;
wire [15:0] ip_header_start = {version, ihl, tos};  // 16'h4500

위와 같이 필드 결합에 사용될 수 있다.

비트 복제 (Replication)

Verilog에서는 비트 패턴 복제도 가능하다.

문법은 {횟수{패턴}} 이다.

(1) 예시

wire        bit1 = 1'b1;
wire [3:0]  nibble = 4'hA;

// 복제 문법: {횟수{패턴}}
wire [7:0]  rep8   = {8{bit1}};       // 8'b11111111 = 8'hFF
wire [15:0] rep4   = {4{nibble}};     // 16'hAAAA
wire [11:0] rep3   = {3{nibble}};     // 12'hAAA

// 복제 + 연결 조합
wire [7:0]  pattern = {4{2'b10}};     // 8'b10101010 = 8'hAA

부호 확장 (Sign Extension)

양수 (MSB=0): 0으로 확장
  8'b0xxx_xxxx → 16'b0000_0000_0xxx_xxxx

음수 (MSB=1): 1로 확장
  8'b1xxx_xxxx → 16'b1111_1111_1xxx_xxxx

위와 같이 부호 확장을 활용하면, 수의 부호와 크기를 유지하며 더 큰 비트수로 나타낼 수 있게된다.

wire [7:0]  small = 8'hF6;    // -10 (signed)
wire [15:0] extended;

// 방법 1: 복제 연산자 사용
assign extended = {{8{small[7]}}, small};
//                  ↑ MSB를 8번 복제

// 방법 2: signed 타입 활용
wire signed [7:0]  small_s = 8'hF6;
wire signed [15:0] extended_s = small_s;  // 자동 부호 확장

// 방법 3: $signed 함수
wire [15:0] extended2 = $signed(small);

부호 확장은 위와 같이 3개의 방식으로 구현할 수 있다.

실전 비트 패턴

(1) 비트 필드 추출/삽입

// 32비트 명령어에서 필드 추출 (RISC-V 예시)
wire [31:0] instruction;
wire [6:0]  opcode = instruction[6:0];
wire [4:0]  rd     = instruction[11:7];
wire [4:0]  rs1    = instruction[19:15];
wire [4:0]  rs2    = instruction[24:20];
wire [6:0]  funct7 = instruction[31:25];

// 필드 삽입 (명령어 생성)
wire [31:0] add_instr = {funct7, rs2, rs1, 3'b000, rd, opcode};

(2) 마스킹

wire [7:0] data = 8'b1010_1100;

// 특정 비트만 추출
wire [7:0] lower4 = data & 8'b0000_1111; // 8'b0000_1100

// 특정 비트만 설정
wire [7:0] set_bit3 = data | 8'b0000_1000; // bit3 = 1

// 특정 비트만 클리어
wire [7:0] clr_bit2 = data & ~8'b0000_0100; // bit2 = 0

// 특정 비트 토글
wire [7:0] toggle = data ^ 8'b0000_1111; // 하위 4비트 반전(1과의 xor은 NOT과 동일)

profile
안녕하세요. 전자공학부 학부생의 공부 기록입니다.

0개의 댓글