Verilog에서 $display 마스터하기: 효과적인 디버깅 및 디스플레이 제어 기법

目次

1. Introduction: The Importance and Purpose of “display” in Verilog

Verilog에서 “display”는 무엇을 의미하나요?

Verilog에서 $display는 시뮬레이션 중 설계의 내부 상태를 “표시”하기 위한 시스템 태스크입니다. C의 printf와 유사하게, 신호, 변수 값, 문자열 등을 터미널이나 콘솔에 출력할 수 있어 디버깅 및 기능 검증에 핵심적인 역할을 합니다.

$display가 Verilog 개발에 필수적인가요?

  • 디버깅 효율성 향상 : 복잡한 회로 설계에서는 내부 신호가 올바르게 동작하는지 시각화하는 것이 중요합니다. $display를 사용하면 시뮬레이션 중 관심 있는 신호의 값을 즉시 확인할 수 있습니다.
  • 시뮬레이션 가시화 : 특정 시점에서 값 변화를 추적할 때 파형만으로는 부족할 수 있습니다. 디스플레이 로그는 그 정확한 순간을 신뢰성 있게 표시해 줍니다.
  • 문서화에도 유용 : 설계 의도나 동작 규칙을 다른 엔지니어에게 전달할 때, 주석이 달린 디스플레이 로그를 삽입하면 코드 이해도를 높일 수 있습니다.

이 글의 목적 및 구성

이 글에서는 다음을 체계적으로 설명합니다.

  1. 기본 문법 및 사용법 : $display의 기본 문법과 사용법을 자세히 소개합니다.
  2. 다른 시스템 태스크와의 비교 : $write, $strobe, $monitor 등 디스플레이 관련 태스크와의 차이점을 정리합니다.
  3. 포맷 지정자와 고급 사용 기법 : %d, %b, %h, %s 등 포맷 지정자와 특수 디스플레이 기법을 소개합니다.
  4. 실용적인 사용 예제 : 테스트벤치와 코드에서의 구체적인 사용 예시를 보여주어 바로 적용 가능한 노하우를 제공합니다.
  5. 디스플레이 제어 응용 : LCD나 모니터 제어와 같은 하드웨어 출력, 텍스트/이미지 출력 예제를 포함합니다.

이와 같은 구성을 통해 초보자와 중급 사용자가 Verilog의 $display를 올바르게 이해하고 실제에 적용할 수 있도록 돕습니다. 이후 각 섹션에서는 가능한 한 예시와 다이어그램을 활용해 명확히 진행합니다.

2. Basics of $display: Syntax, Use-Cases, and Precautions

$display 기본 문법

Verilog에서 $display를 사용할 때 기본 문법은 다음과 같습니다.

$display("string or format specifiers", signal1, signal2, ...);
  • 문자열 부분 : 텍스트나 포맷 지정자(예: %d, %b, %h)를 작성합니다.
  • 인자 : 해당 포맷에 맞춰 출력할 신호명이나 변수명을 나열합니다.

예시: 클럭 카운트와 신호 값을 표시하기

$display("Time=%0t : clk=%b, reset=%b", $time, clk, reset);

위 예시에서는 시뮬레이션 시간과 클럭/리셋 신호의 값이 출력됩니다.

$display 활용 사례

  1. 시뮬레이션 진행 상황 파악 : 설계의 특정 지점에 $display를 삽입하면 코드가 어느 부분까지 실행되었는지 확인할 수 있습니다.
  2. 신호 값 검증 : 파형 뷰어만으로는 조건 분기나 상태 전이를 직관적으로 이해하기 어려울 때, 텍스트 출력으로 이해도를 높일 수 있습니다.
  3. 조건부 메시지 출력 : if 문과 결합해 특정 조건이 만족될 때만 로그를 남길 수 있습니다. if (reset) $display("Reset asserted at %0t", $time);

$display$write의 차이점

$display는 출력 끝에 자동으로 개행(newline)을 추가합니다. 반면 $write는 개행 없이 연속해서 출력합니다.
예시:

$display("Hello");
$display("World");

출력:

Hello
World
$write("Hello");
$write("World");

출력:

HelloWorld

줄 단위로 명확한 로그가 필요하면 $display를 사용하고, 한 줄에 여러 값을 포맷팅해서 출력하고 싶다면 $write를 사용하세요.

사용 시 주의사항

  1. 과도한 출력 방지 매 클럭 사이클마다 $display를 사용하면 로그가 크게 증가하고 가독성이 떨어집니다. → 출력량을 줄이기 위해 조건부 출력을 사용하세요.
  2. 시간 표시 활용 $time이나 $realtime을 출력하면 연산의 타이밍을 정확히 파악할 수 있습니다.
  3. 시뮬레이션 전용 태스크 $display는 합성(FPGA/ASIC 구현)에서 사용할 수 없습니다. 순수히 시뮬레이션 디버깅용 도구입니다.

3. 로그 출력 시스템 태스크 비교: $display, $write, $strobe, $monitor

Verilog는 $display 외에도 다양한 시스템 태스크를 제공하여 출력을 제어합니다. 각각의 사용 사례와 타이밍을 이해하면 효율적으로 활용할 수 있습니다.

$display: 표준 디스플레이 태스크

  • 특징 자동으로 개행을 추가하고 호출당 한 줄을 기록합니다.
  • 사용 사례 가장 기본적인 디버그 방법으로, 언제든지 한 번의 출력이 필요할 때 사용합니다.

$write: 개행 없이 출력

  • 특징 개행을 추가하지 않으므로 같은 줄에 계속 출력됩니다.
  • 사용 사례 여러 값을 나란히 표시하고 싶을 때 유용합니다.
  • 예시 $write("A=%d, ", a); $write("B=%dn", b); → 출력: A=5, B=10

$strobe: 시뮬레이션 사이클 종료 시 출력

  • 특징 현재 단계의 모든 시뮬레이션 평가가 끝난 뒤 값을 출력합니다.
  • 사용 사례 레이스 컨디션을 피하고 싶을 때(여러 신호가 동시에 변할 때) 유용합니다.
  • 예시 $strobe("Time=%0t, signal=%b", $time, sig);$display가 중간값을 보여줄 수 있는 반면, $strobe는 안정된 값을 보여줍니다.

$monitor: 자동 추적 출력

  • 특징 모니터링 대상 신호가 변할 때마다 자동으로 출력합니다.
  • 사용 사례 여러 신호를 지속적으로 감시하고 싶을 때 편리합니다.
  • 예시 $monitor("At %0t: a=%b, b=%b", $time, a, b);a 또는 b가 변할 때마다 로그가 기록됩니다.

요약 표

태스크개행출력 타이밍주요 사용 사례
$display호출 시기본 로그 출력
$write아니오호출 시나란히 포맷팅
$strobe시뮬레이션 사이클 종료 후안정된 값 확인
$monitor신호 변동 시 자동지속적인 모니터링

효과적인 사용 팁

  • 기본적으로 $display 사용 : 가독성이 좋고 초보자에게 쉬움.
  • 한 줄에 결합된 출력을 원한다면 $write 사용 .
  • 변경 후 안정된 값을 보고 싶다면 $strobe 사용 .
  • 신호를 지속적으로 감시해야 한다면 $monitor 사용 .

4. 포맷 지정자와 고급 디스플레이 기법

$display$write와 같은 태스크에서는 문자열 안에 “포맷 지정자”를 넣어 신호나 변수를 원하는 형식으로 출력할 수 있습니다. C의 printf와 유사하므로 목적에 맞게 올바르게 사용하면 디버깅 효율이 크게 향상됩니다.

기본 포맷 지정자

지정자설명출력 예시
%b2진수1010
%d10진수10
%h16진수A
%o8진수12
%cASCII 문자A
%s문자열Hello
%t시뮬레이션 시간#100
%m모듈 계층 이름top.u1.u2

실용 예시

  1. 신호를 여러 형식으로 출력
    verilog reg [7:0] data = 8'b10101010; $display("data = %b (bin), %d (dec), %h (hex)", data, data, data);
    → 예시 출력: data = 10101010 (bin), 170 (dec), AA (hex)

  2. 모듈 계층 확인
    verilog $display("Current module hierarchy is %m");
    → 예시 출력: Current module hierarchy is top.u1.counter

  3. 시뮬레이션 시간 출력
    verilog $display("Time=%0t: clk=%b", $time, clk);
    → 예시 출력: Time=100: clk=1

고급 디스플레이 기법

  • Zero‑padding 및 필드 너비 %0d 와 같이 제로 패딩이나 필드 너비를 지정할 수 있습니다. 예시: $display("Count=%04d", count); → 출력: Count=0012
  • Signed vs unsigned 구분 %d 는 값을 부호 있는(signed) 것으로, %u 는 부호 없는(unsigned) 것으로 처리합니다. 음수 값이 예상대로 표시되지 않으면 지정자를 수정하세요.
  • 다중 라인 메시지 포맷팅 가독성을 위해 \n 을 사용해 줄바꿈합니다. 예시: $display("Start of test\nSignal A=%b\nSignal B=%b", A, B);

주의 사항

  • 비트 폭에 유의 : Verilog 신호는 폭이 서로 다를 수 있으며, %d 를 사용하면 트렁케이션이나 부호 확장 문제가 발생할 수 있습니다.
  • 정의되지 않은 값 (X, Z) 처리 : 정의되지 않은 비트를 포함하면 %bx 혹은 z 가 직접 표시됩니다.

5. 실용 예제: 테스트벤치와 모듈에서 $display 사용하기

이제 실제 Verilog 코드 예제를 통해 테스트벤치부터 조건부 디버그 로깅까지 $display 의 효과적인 활용 방법을 소개합니다.

기본 예제: 테스트벤치에서 출력하기

테스트벤치에 $display 를 삽입하면 시뮬레이션 중 동작을 관찰할 수 있습니다.

module tb_counter;
  reg clk;
  reg reset;
  wire [3:0] count;

  // DUT (Device Under Test)
  counter uut (
    .clk(clk),
    .reset(reset),
    .count(count)
  );

  // Clock generation
  initial begin
    clk = 0;
    forever #5 clk = ~clk;  // invert every 5 units
  end

  // Test scenario
  initial begin
    reset = 1;
    #10 reset = 0;

    #50 $finish;
  end

  // Display state
  always @(posedge clk) begin
    $display("Time=%0t | reset=%b | count=%d", $time, reset, count);
  end
endmodule

이 예제에서는 상승하는 클럭마다 resetcount 가 출력됩니다. 텍스트 로그와 파형을 동시에 확인할 수 있어 동작 추적이 쉬워집니다.

조건부 디스플레이 예제

if 문과 결합하면 특정 조건이 만족될 때만 로그를 남길 수 있습니다.

always @(posedge clk) begin
  if (count == 4'd10) begin
    $display("Count has reached 10 (Time=%0t)", $time);
  end
end

→ 불필요한 로그를 피하면서 관심 있는 이벤트만 정확히 파악할 수 있습니다.

디버그 메시지 예제

설계 디버깅 시 신호가 “예상치 못한 상태”에 들어갔을 때 이를 포착하는 것이 효과적입니다.

always @(posedge clk) begin
  if (count > 4'd12) begin
    $display("WARNING: count overflow detected! Time=%0t, value=%d", $time, count);
  end
end

→ 설계 결함이나 예상치 못한 시뮬레이션 동작을 빠르게 발견할 수 있습니다.

여러 신호를 동시에 모니터링하기

많은 신호를 출력할 때 $display 로 한 줄에 모아 출력하면 로그 가독성이 향상됩니다.

$display("Time=%0t | clk=%b | reset=%b | A=%h | B=%h | SUM=%h",
         $time, clk, reset, A, B, SUM);

실용 팁 요약

  • 테스트벤치에 $display 를 배치해 진행 상황을 시각화
  • 조건문을 활용해 로그를 정제
  • 경고 메시지를 생성해 이상 징후를 탐지
  • 여러 신호를 한 줄에 통합해 가독성 개선

6. 디스플레이 제어 응용 (픽셀/텍스트/이미지 디스플레이)

지금까지 시뮬레이션 로그용 $display 를 소개했습니다. 한편 Verilog는 하드웨어 구현에서도 “디스플레이 제어”(LCD, VGA, HDMI 출력) 용도로 널리 사용됩니다. 이 섹션에서는 하드웨어 수준에서 화면 디스플레이를 구현하는 방법을 간략히 소개합니다.

디스플레이 제어의 기본 개념

화면에 텍스트나 이미지를 표시하려면 $display 가 아니라 비디오 신호를 생성해야 합니다. 일반적인 제어 신호는 다음과 같습니다:

  • HSYNC (Horizontal Sync) : 각 라인의 끝을 나타내는 신호
  • VSYNC (Vertical Sync) : 각 프레임의 끝을 나타내는 신호
  • RGB Data : 각 픽셀의 색상을 나타내는 신호 (예: 8bit × 3 = 24bit 컬러)

Verilog에서는 카운터와 상태 머신을 이용해 이러한 신호를 타이밍에 맞춰 제어하고 출력함으로써 “스크린 디스플레이”를 구현합니다.

예제 1: 컬러 바 표시하기

가장 기본적인 예는 디스플레이에 색상 막대를 가로로 출력하는 것입니다.

always @(posedge clk) begin
  if (h_counter < 100)       rgb <= 24'hFF0000; // red
  else if (h_counter < 200)  rgb <= 24'h00FF00; // green
  else if (h_counter < 300)  rgb <= 24'h0000FF; // blue
  else                       rgb <= 24'h000000; // black
end

→ 이는 화면을 가로로 정렬된 빨강, 초록, 파랑 색상 막대로 표시합니다.

예제 2: 텍스트 디스플레이

텍스트 디스플레이를 위해 폰트 ROM을 준비하고 각 문자들의 점 패턴을 픽셀로 변환합니다.

// Referencing the pattern of 'A' from the font ROM and displaying
if (font_rom[char_code][y][x] == 1'b1)
    rgb <= 24'hFFFFFF;  // white for display
else
    rgb <= 24'h000000;  // black background

→ 이는 특정 문자(예: “A”)를 화면에 그립니다.

예제 3: 이미지 디스플레이

이미지를 표시하려면 미리 저장된 비트맵 데이터(ROM 또는 외부 메모리)를 읽어 픽셀 출력으로 변환합니다.

rgb <= image_rom[addr];  // Retrieve color data from ROM

FPGA를 사용하는 임베디드 시스템에서 이 방법으로 간단한 아이콘이나 로고를 표시할 수 있습니다.

디버그 $display와의 차이점

  • $display텍스트 출력(시뮬레이션 전용)입니다.
  • 디스플레이 제어는 비디오 신호 생성(하드웨어 구현 가능)입니다.

목적은 다르지만 Verilog 학습자들은 두 가지를 혼동하기 쉽습니다.

  • “시뮬레이션 중 동작을 검증하고 싶다” → $display 사용
  • “FPGA에서 실제 화면에 출력하고 싶다” → 비디오 신호 로직 설계

응용 분야 확장

  • FPGA 보드를 학습할 때 Verilog는 7세그먼트 LED 디스플레이 또는 소형 LCD 디스플레이에 자주 사용됩니다.
  • 더 나아가 VGA/HDMI 출력을 지원하는 시스템을 구축하여 게임 개발이나 GUI 디스플레이에 활용할 수 있습니다.
  • $display에 대한 지식과 디스플레이 제어 로직을 결합하면 시뮬레이션과 실제 하드웨어 모두에서 “디스플레이”를 다룰 수 있습니다.

7. 적용 시나리오에 따른 적절한 사용법 및 팁

Verilog에서 “디스플레이”라고 할 때는 두 가지 측면이 있습니다: 시뮬레이션 전용 $display 작업하드웨어 구현 디스플레이 제어. 각각을 적절히 사용하면 효율적인 개발 및 디버깅이 가능합니다.

시뮬레이션에서의 사용

  1. 디버그 로그로서의 $display
    • $display를 사용해 중요한 변수나 신호를 출력하여 설계가 기대대로 동작하는지 확인합니다.
    • “특정 조건에서의 값”이나 “카운터가 특정 지점에 도달했는지”를 로그로 검증하는 것이 효율적입니다.
  2. 과도한 출력 피하기
    • 매 클럭 사이클마다 출력하면 로그가 범람하고 가독성이 떨어집니다. 조건을 좁혀 출력합니다.
    • 예시: if (state == ERROR) $display("Error occured at %0t", $time);
  3. 작업 구분하기
    • $monitor → 지속적으로 감시하고 싶은 신호에 사용
    • $strobe → 안정된 값을 출력하고 싶을 때 사용
    • $write → 가로형 포맷 출력에 사용

하드웨어 디스플레이 제어에서의 사용

  1. 학습용 7세그먼트 디스플레이
    • FPGA 초급 프로젝트에서 카운터 값을 7세그먼트 LED에 표시하는 것이 일반적입니다.
    • $display 시뮬레이션 출력과 결합하면 디스플레이와 시뮬레이션의 차이를 깊이 이해할 수 있습니다.
  2. LCD 또는 VGA 모니터 제어
    • 폰트 ROM이나 이미지 ROM을 사용해 텍스트나 이미지를 표시합니다.
    • 시뮬레이션에서도 $display를 활용하면 비디오 신호 생성이 올바른지 두 번 확인할 수 있습니다.
  3. 하드웨어 디버그 오버레이
    • 실제 비디오 출력에 “카운터 값”, “좌표”, “디버그 메시지” 등을 오버레이할 수 있습니다.
    • FPGA 개발에서는 화면 자체를 디버깅 도구로 만드는 것이 일반적입니다.

실용적인 팁

  • 시뮬레이션 → 하드웨어 흐름 따라가기 먼저 $display를 사용해 시뮬레이션에서 동작을 검증하고, 이후 하드웨어 구현을 위한 디스플레이 제어 로직으로 이동합니다.
  • 로그와 파형을 함께 사용 $display의 텍스트 로그는 “이벤트 발생 시점”을 나타내고, 파형은 “세부 전이”를 보여줍니다. 두 가지를 함께 사용하면 디버깅 정밀도가 높아집니다.
  • 팀 개발에서 메시지 형식 통일 $display 메시지 형식(접두사, 시간 표시 등)을 표준화하면 여러 사람이 작업할 때 로그 분석이 쉬워집니다.

요약

  • $display 유형 작업은 시뮬레이션 전용 “관찰 도구”입니다.
  • 디스플레이 제어는 하드웨어 구현 “디스플레이 방법”을 의미합니다.
  • 각각을 적절히 사용하고 결합하면 효율적인 개발이 가능합니다.

8. FAQ (자주 묻는 질문)

Q1. $display$monitor의 차이점은 무엇인가요?

A. $display는 호출된 순간에 한 번 출력합니다. 반면 $monitor는 등록된 신호가 변할 때마다 자동으로 출력합니다.

  • 일회성 디버깅 → $display
  • 지속적인 모니터링 → $monitor

Q2. 언제 $strobe를 사용해야 하나요?

A. $strobe는 시뮬레이션 사이클이 끝날 때 안정된 값을 출력합니다. 예를 들어 클럭 엣지에서 여러 신호가 동시에 변할 경우 $display는 중간 값을 보여줄 수 있습니다. 이런 경우 최종 값을 표시하기에 $strobe가 편리합니다.

Q3. 포맷 지정자 %m의 용도는 무엇인가요?

A. %m은 현재 모듈 계층 구조 이름을 출력합니다. 큰 설계에서는 “메시지가 어느 계층에서 왔는지”를 로그에 남기는 것이 분석을 훨씬 쉽게 해줍니다.

$display("Current module: %m");

예시 출력:

Current module: top.u1.counter

Q4. $display를 많이 사용해서 로그가 방대해졌어요. 어떻게 해야 하나요?

A. 다음과 같은 방법이 효과적입니다:

  • if 문을 사용해 출력 필터링
  • 오류 감지나 특정 이벤트만 출력
  • $monitor를 사용해 최소한의 필수 신호만 감시
  • 로그 파일에 출력하고 분석 시 필터링 도구 적용

Q5. $display를 합성(FPGA/ASIC)에서 사용할 수 있나요?

A. 아닙니다. $display시뮬레이션 전용 작업입니다. 합성 도구는 이를 무시하므로 실제 하드웨어에 반영되지 않습니다. 실제 하드웨어에 출력을 표시하려면 Verilog에서 “7-세그먼트 LED”, “LCD”, “VGA 제어 로직” 등을 설계해야 합니다.

Q6. 실제 하드웨어에 텍스트나 이미지를 어떻게 표시하나요?

A. $display가 아니라 비디오 신호를 생성해서 합니다.

  • 7-세그먼트 디스플레이 → 간단한 숫자나 문자 표시용
  • VGA/LCD → HSYNC, VSYNC, RGB 신호를 생성하고 제어
  • 텍스트 → 폰트 ROM을 사용해 점 패턴 출력
  • 이미지 → 비트맵을 ROM이나 외부 메모리에 저장하고 픽셀을 출력

9. 결론 및 다음 단계

이 글의 요약

이 글에서는 Verilog의 “디스플레이”를 기본 개념부터 응용까지 다루었습니다. 주요 내용은 다음과 같습니다:

  1. $display 기본
    • 신호나 변수를 표시하는 시뮬레이션 작업으로, C의 printf와 유사하게 사용할 수 있습니다.
  2. 관련 작업과의 차이점
    • $write → 줄바꿈 없이 표시
    • $strobe → 시뮬레이션 사이클 종료 시 안정된 값 출력
    • $monitor → 신호 변화 자동 감시
  3. 포맷 지정자 사용
    • %b, %d, %h, %m, %t 등을 사용하면 더 명확하고 실용적인 로그를 출력할 수 있습니다.
  4. 실용 예제
    • 테스트벤치에 $display를 삽입해 진행 상황을 모니터링합니다.
    • 조건부 메시지를 사용해 효율적인 디버깅을 가능하게 합니다.
  5. 디스플레이 제어 적용
    • $display는 시뮬레이션 전용이며, 하드웨어 구현은 HSYNC, VSYNC, RGB를 사용해 텍스트/이미지를 출력합니다.
    • 7-세그먼트 디스플레이 학습부터 고급 VGA/HDMI 제어까지 확장이 가능합니다.

다음 단계

  • SystemVerilog로 진보 → 후속 언어인 SystemVerilog에서는 더 고급 디버그 기능(어설션, 향상된 $display 등)을 사용할 수 있습니다.
  • 파형 뷰어와 결합$display 로그와 파형 데이터를 결합하면 수치값과 전이 모두를 분석할 수 있어 디버깅 정밀도가 향상됩니다.
  • 하드웨어 디스플레이 출력 학습 → 작은 FPGA 보드 프로젝트에서 7세그먼트나 LCD에 출력해 보면서 “시뮬레이션 디스플레이”와 “하드웨어 디스플레이 제어”의 차이를 체험해 보세요.
  • 팀 개발에 적용$display 메시지 형식을 표준화함으로써 다인 개발에서 로그 분석 효율을 높일 수 있습니다.

마무리

$display는 단순한 “텍스트 출력” 그 이상입니다. 시뮬레이션 디버깅을 위한 강력한 도구이며, 디스플레이 제어 세계에 들어가면 FPGA를 통해 실제 모니터에 그래픽을 표시하는 즐거움을 경험할 수 있습니다.

이 글이 Verilog 학습자들이 “시뮬레이션 디버깅”과 “하드웨어 디스플레이 출력”을 명확히 이해하는 데 도움이 되길 바랍니다.