Verilog의 C printf 일족
세 시스템 태스크가 시뮬레이터의 stdout에 출력합니다.
$display- 한 번 출력, 줄바꿈 추가.$write- 한 번 출력, 줄바꿈 없음.$monitor- 관찰된 신호가 변할 때마다 자동으로 출력.
세 모두 printf처럼 format string과 인자 목록을 받습니다. format specifier는 비슷하지만 Verilog 특유입니다.
$display: 기본
$display는 일꾼입니다.
대략 이런 것을 보게 됩니다.
Hello, world.
byte_val = ab
byte_val = 10101011
byte_val = 171
byte_val = 171 (no padding)
multi: nibble=1010 count=42
메모.
%d는 피연산자 크기 기반 기본 너비로 패딩합니다. 8비트reg라면 3자(255 들어갈 공간). 표 출력에서 보기 흉할 수 있어%0d로 억제하세요.%h,%b,%o도 기본 패딩이 비슷합니다. 정렬이 유용하지 않으면 testbench 코드 대부분이%0변형을 씁니다.- 줄 끝의 줄바꿈은 자동.
$display의 format string 끝에\n을 두지 마세요 - 빈 줄이 생깁니다.
Format Specifier
Verilog이 지원하는 세트.
| Specifier | 의미 |
|---|---|
%b | binary |
%d | decimal (신호가 signed면 signed) |
%h 또는 %x | hex |
%o | octal |
%c | 단일 ASCII 문자 (low 8비트) |
%s | string |
%t | 시뮬레이션 시간 |
%m | 현재 스코프의 계층 이름 |
%% | literal % |
%0X | leading 패딩 없음, %b, %d 등 어느 쪽이든 |
%b, %d, %h, %o가 95% 쓰게 될 넷입니다. %t가 그다음으로 흔합니다 - timestamp가 찍힌 로그 줄을 원할 때마다.
$write: 줄바꿈 없음
$write는 줄바꿈을 추가하지 않는 점 빼고 $display와 같습니다.
출력.
abc
done
루프 본문으로부터 한 줄을 만드는 데 유용.
$write("[");
for (integer i = 0; i < 8; i = i + 1) $write("%h ", arr[i]);
$display("]");
$monitor: 변경 시 자동 출력
$monitor는 watch list를 등록합니다. format string에 언급된 어떤 신호든 변할 때마다 시뮬레이터가 다시 평가하고 출력합니다.
입력 변경마다 한 줄씩 세 줄을 봅니다. 자극 변경 후 수동으로 $display를 호출할 필요 없음 - $monitor가 해 줍니다.
두 가지 제한.
- 한 번에 활성인
$monitor는 하나뿐. 다시 호출하면 이전 watch list가 대체됩니다. 일시 억제와 재활성에는$monitoroff와$monitoron사용. - 같은 time step 안의 변경은 출력 하나로 합쳐짐. 시간 5에
a와b가 둘 다 변하면 monitor가 두 번이 아니라 한 번 발사되어 두 새 값을 함께 출력.
각각 언제 쓸까
$display: 대부분의 testbench 출력. 자극 후, 중요한 상태 전이 후, 또는 samplingalways @(posedge clk)블록 안에서 명시적으로 호출.$write: 루프나 여러 작은 조각으로부터 한 줄을 만들 때.$monitor: 작은 신호 집합을 연속적으로 추적하고 변할 때만 출력 보고 싶을 때. 초기 디버깅에 유용; 출력이 줄 수 측면에서 결정적이지 않아 regression 스크립트에는 다루기 어려움.
대부분의 워크플로에서는 $display로 충분합니다. 진짜로 연속적인 변경 기반 출력을 원할 때만 $monitor로 손이 갑니다.
시간 다루기
$time은 현재 시뮬레이션 시간을 64비트 정수로 반환합니다. %0t와 짝지으세요.
$display("at %0t: signal flipped", $time);
출력은 at 25: signal flipped처럼 보입니다(단위는 timescale에 따름).
sub-tick 정밀도가 필요하다면(드묾) 대신 $realtime을 쓰세요 - real을 반환합니다.
%t는 시뮬레이터가 고른 기본 너비로 시간을 자동 형식화합니다. %0t가 패딩을 벗깁니다.
클럭 edge에서 sampling
순차 설계를 모니터링하는 깔끔한 idiom: 사이클마다 한 번 출력하는 별도 always @(posedge clk) 블록.
이 sampling 패턴은 클럭당 로그 한 줄을 보장합니다 - 출력에 패턴 매칭하는 regression 테스트에 완벽.
파일에 로깅
$fopen으로 파일을 열고, $fdisplay(파일 핸들에 쓰는 점 빼고 $display처럼 동작)로 로깅.
integer fd;
initial begin
fd = $fopen("results.txt", "w");
$fdisplay(fd, "test=%s status=%s", test_name, status);
$fclose(fd);
end
$fopen은 32비트 핸들을 반환합니다. $fdisplay, $fwrite, $fstrobe 등의 첫 인자로 전달하세요. 함수는 그 외에는 콘솔 출력 형제들과 동일합니다.
다음에 볼 내용
$display와 친구들이 텍스트 로그를 줍니다. 시각적 디버깅 - 신호를 시간에 따른 전압으로 보기 - 에는 VCD 파형이 필요합니다. 다음 문서 Dumpfile and VCD는 시뮬레이션을 스크럽 가능한 그래픽 파형으로 만드는 두 호출 $dumpfile과 $dumpvars를 다룹니다.
자주 묻는 질문
Verilog의 $display와 $monitor 차이는?
$display는 실행될 때 한 번 즉시 출력합니다 - C의 printf와 비슷. $monitor는 watch list를 등록합니다; list의 어떤 신호든 변할 때마다 형식 메시지가 자동으로 출력됩니다. 한 번에 활성인 $monitor는 하나뿐이며, 다시 호출하면 이전 watch list가 대체됩니다.
Verilog $display는 어떤 format specifier를 지원하나요?
흔한 것들: %b(binary), %d(decimal), %h(hex), %o(octal), %c(low 바이트의 단일 문자), %s(string), %t(시뮬레이션 시간), %m(계층 인스턴스 이름). 0 패딩을 없애려면 %0d 형태를 쓰세요 - %d는 기본 너비로 패딩하고 %0d는 패딩하지 않습니다.
Verilog의 $write란?
$write는 $display와 비슷하지만 줄바꿈을 추가하지 않습니다. 여러 호출로부터 한 줄의 출력을 만들고 싶을 때 유용합니다. 줄 끝의 $display(인자 없거나 줄바꿈 있는)가 줄을 종료합니다.
Verilog에서 시뮬레이션 시간은 어떻게 출력하나요?
%t format specifier와 함께 $time(또는 sub-tick 해상도가 필요하면 $realtime)을 사용합니다: $display("at time %t: ...", $time);. 기본 패딩을 없애려면 %0t. 시간 단위의 평범한 정수 카운트라면 $time과 %0d도 됩니다: $display("t=%0d", $time);.