[Verilog 문법] 2.4 조건문

YUN·2026년 1월 21일

디지털 회로 설계

목록 보기
9/20
post-thumbnail

1. 조건문

조건에따라 다른 동작을 수행하는 구문

HW 적으로는 MUX로 합성된다.

2. if 문

if (조건1)
    문장1;
else if (조건2)
    문장2;
else if (조건3)
    문장3;
else
    문장4;    // 기본값

if 문은 위와 같은 문법으로 코드를 짜면된다.

만약 각 if,else if, else 문 내부에 한 줄이 아니라 여러 줄의 코드를 적고 싶은 경우

begin-end 블록을 사용하면된다.

(1) begin-end 블록

여러 문장을 묶을 때 사용한다

if (조건) begin
    문장1;
    문장2;
    문장3;
end
else begin
    문장4;
    문장5;
end

위와 같이 begin~end 블록을 사용하면 if, else if, else 문 내부에 한 줄이 아니라 여러 줄의 코드를 적을 수 있다.

(2) 활용 예시

2:1 MUX

// 조합 논리
always @(*) begin
    if (sel)
        y = b;
    else
        y = a;
end

우선순위 인코더

always @(*) begin
    if (req[3])
        grant = 2'd3;
    else if (req[2])
        grant = 2'd2;
    else if (req[1])
        grant = 2'd1;
    else if (req[0])
        grant = 2'd0;
    else
        grant = 2'd0;
end

(3) 주의 : 의도치 않은 래치의 생성을 조심해야한다.

// ❌ 래치 발생!
always @(*) begin
    if (sel)
        y = a;
    // else 없음 → y가 유지됨 → 래치!
end

// ✅ 래치 방지
always @(*) begin
    if (sel)
        y = a;
    else
        y = b;    // 모든 경로 커버
end

// ✅ 디폴트 값 패턴
always @(*) begin
    y = b;        // 디폴트 먼저
    if (sel)
        y = a;
end

순차 논리에서는 메모리 특성이 있는게 정상이므로 굳이 else 쓸 필요 없다.

3. case 문

조건에따라 다른 동작을 수행하는 구문

case 문은 if 문보다 가독성이 좋고, 병렬 선택 구조이다.

(1) 문법

case (선택신호)
    값1: 문장1;
    값2: 문장2;
    값3: 문장3;
    default: 기본문장;
endcase

case문에서도, 각 case에 여러 문장을 적고싶다면 begin-end 블록을 활용하면된다.

(2) 활용 예시

4:1 MUX

always @(*) begin
    case (sel)
        2'b00: y = a;
        2'b01: y = b;
        2'b10: y = c;
        2'b11: y = d;
    endcase
end

ALU

module alu (
    input  wire [7:0] a, b,
    input  wire [2:0] op,
    output reg  [7:0] result
);

    always @(*) begin
        case (op)
            3'b000: result = a + b;     // ADD
            3'b001: result = a - b;     // SUB
            3'b010: result = a & b;     // AND
            3'b011: result = a | b;     // OR
            3'b100: result = a ^ b;     // XOR
            3'b101: result = ~a;        // NOT
            3'b110: result = a << 1;    // SHL
            3'b111: result = a >> 1;    // SHR
        endcase
    end

endmodule

(3) 주의 : 의도치 않은 래치의 생성을 조심해야한다.

앞서 if문에서와 마찬가지로, 조합 논리 회로의 경우, 의도치 않은 래치의 생성을 조심해야한다.

이를 위해 case문의 마지막에 default를 추가해주면 된다.

3. casez

z (고임피던스)를 don't care로 처리하는 case문

?dont' care 표기로 사용한다.

always @(*) begin
    casez (opcode)
        4'b1???: y = a;     // 상위 1비트가 1이면 (나머지 무관)
        4'b01??: y = b;     // 상위 2비트가 01이면
        4'b001?: y = c;     // 상위 3비트가 001이면
        4'b0001: y = d;     // 정확히 0001
        default: y = 8'b0;
    endcase
end

위와 같이 사용할 수 있다.

(1) 예시

명령어 디코더

always @(*) begin
    casez (instruction[15:12])
        4'b0000: alu_op = ADD;
        4'b0001: alu_op = SUB;
        4'b001?: alu_op = AND;    // 0010, 0011 둘 다 AND
        4'b01??: alu_op = LOAD;   // 0100~0111 모두 LOAD
        4'b1???: alu_op = JUMP;   // 1000~1111 모두 JUMP
        default: alu_op = NOP;
    endcase
end

4. casex

x (불확정)와 z 모두 don't care 로 처리

always @(*) begin
    casex (data)
        4'b1xxx: result = 1;    // 최상위 비트가 1이면
        4'b01xx: result = 2;
        4'b001x: result = 3;
        4'b0001: result = 4;
        default: result = 0;
    endcase
end

위와 같이 사용할 수 있다.

5. 삼항연산자

한 줄로 표현하는 if-else 문

(1) 문법

결과 = 조건 ? 참일때값 : 거짓일때값;

(2) 예시

// if-else 버전
always @(*) begin
    if (sel)
        y = b;
    else
        y = a;
end

// 삼항 연산자 버전 (위의 if-else문과 동일하다)
assign y = sel ? b : a;

(3) 중첩 삼항 연산자

// 4:1 MUX
assign y = (sel == 2'b00) ? a :
           (sel == 2'b01) ? b :
           (sel == 2'b10) ? c :
                            d ;


  중첩 구조:
  
  sel==00? ──yes──▶ a
     │
     no
     ↓
  sel==01? ──yes──▶ b
     │
     no
     ↓
  sel==10? ──yes──▶ c
     │
     no
     ↓
     d

이런식으로 삼항 연산자를 중첩해서 사용할수도 있다.

6. 관련 예제 : 간단한 CPU 제어

module simple_control (
    input  wire [3:0] opcode,
    input  wire       zero_flag,
    output reg        reg_write,
    output reg        mem_read,
    output reg        mem_write,
    output reg        branch,
    output reg  [1:0] alu_op
);

    // 명령어 정의
    localparam ADD  = 4'b0000;
    localparam SUB  = 4'b0001;
    localparam AND  = 4'b0010;
    localparam OR   = 4'b0011;
    localparam LW   = 4'b0100;  // Load Word
    localparam SW   = 4'b0101;  // Store Word
    localparam BEQ  = 4'b0110;  // Branch if Equal
    localparam BNE  = 4'b0111;  // Branch if Not Equal

    always @(*) begin
        // 디폴트 값 (래치 방지)
        reg_write = 1'b0;
        mem_read  = 1'b0;
        mem_write = 1'b0;
        branch    = 1'b0;
        alu_op    = 2'b00;

        case (opcode)
            ADD, SUB, AND, OR: begin
                reg_write = 1'b1;
                alu_op    = opcode[1:0];
            end
            
            LW: begin
                reg_write = 1'b1;
                mem_read  = 1'b1;
            end
            
            SW: begin
                mem_write = 1'b1;
            end
            
            BEQ: begin
                branch = zero_flag;     // 같으면 분기
            end
            
            BNE: begin
                branch = ~zero_flag;    // 다르면 분기
            end
            
            default: begin
                // 디폴트 값 유지
            end
        endcase
    end

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

0개의 댓글