Keluarga printf ala Verilog
Ada tiga system task untuk mencetak ke stdout simulator:
$display: mencetak sekali, menambahkan baris baru.$write: mencetak sekali, tanpa baris baru.$monitor: mencetak otomatis setiap kali sinyal yang dipantau berubah.
Ketiganya menerima format string dan daftar argumen, persis seperti printf. Format specifier-nya mirip, tapi khas Verilog.
$display: Pilihan Default
$display adalah andalan utamanya:
Kamu akan melihat kira-kira seperti ini:
Hello, world.
byte_val = ab
byte_val = 10101011
byte_val = 171
byte_val = 171 (no padding)
multi: nibble=1010 count=42
Catatan:
%dmemberi padding sampai lebar default berdasarkan ukuran operand. Untukreg8-bit, itu 3 karakter (cukup untuk255). Spasi di depannya bisa terlihat jelek di output berbentuk tabel; pakai%0duntuk menghilangkannya.%h,%b,%ojuga punya padding serupa secara default. Kebanyakan kode testbench memakai varian%0saat perataan itu tidak berguna.- Baris baru di akhir ditambahkan otomatis. Jangan taruh
\ndi akhir format string$display, karena kamu akan mendapat baris kosong.
Format Specifier
Daftar yang didukung Verilog:
| Specifier | Arti |
|---|---|
%b | biner |
%d | desimal (signed kalau sinyalnya signed) |
%h atau %x | hex |
%o | oktal |
%c | satu karakter ASCII (8 bit terendah) |
%s | string |
%t | waktu simulasi |
%m | nama hierarkis dari scope saat ini |
%% | karakter % literal |
%0X | tanpa padding di depan, untuk %b, %d, dan lainnya |
%b, %d, %h, %o adalah empat yang akan kamu pakai 95% dari waktu. %t yang paling umum berikutnya, setiap kali kamu ingin baris log dengan cap waktu.
$write: Tanpa Baris Baru
$write sama persis dengan $display, hanya saja tidak menambahkan baris baru:
Output:
abc
done
Berguna untuk membangun satu baris dari isi sebuah loop:
$write("[");
for (integer i = 0; i < 8; i = i + 1) $write("%h ", arr[i]);
$display("]");
$monitor: Mencetak Otomatis saat Berubah
$monitor mendaftarkan daftar pantauan. Simulator mengevaluasi ulang dan mencetak setiap kali sinyal apa pun yang disebut di format string berubah:
Kamu akan melihat tiga baris, satu untuk setiap perubahan input. Tidak perlu memanggil $display secara manual setelah setiap perubahan stimulus, karena $monitor yang melakukannya.
Dua keterbatasannya:
- Hanya satu
$monitoryang bisa aktif. Memanggilnya lagi akan mengganti daftar pantauan sebelumnya. Pakai$monitoroffdan$monitoronuntuk menonaktifkan sementara dan mengaktifkannya kembali. - Perubahan dalam langkah waktu yang sama digabung menjadi satu cetakan. Kalau
adanbsama-sama berubah pada waktu 5, monitor mencetak sekali dengan kedua nilai baru, bukan dua kali.
Kapan Memakai Masing-Masing
$display: sebagian besar output testbench. Panggil secara eksplisit setelah stimulus, setelah transisi state yang penting, atau di dalam blokalways @(posedge clk)yang mengambil sampel.$write: saat kamu ingin membangun satu baris dari loop atau beberapa potongan kecil.$monitor: saat kamu ingin memantau sekumpulan kecil sinyal terus-menerus dan hanya melihat output saat sinyalnya berubah. Berguna untuk debug awal; lebih sulit dipakai di skrip regresi karena jumlah total baris output-nya tidak deterministik.
Untuk kebanyakan alur kerja, $display sudah mencakup semuanya. Pakai $monitor hanya kalau output yang dipicu perubahan secara terus-menerus memang benar-benar yang kamu inginkan.
Bekerja dengan Waktu
$time mengembalikan waktu simulasi saat ini sebagai integer 64-bit. Pasangkan dengan %0t:
$display("at %0t: signal flipped", $time);
Output-nya terlihat seperti at 25: signal flipped (satuannya bergantung pada timescale-mu).
Kalau kamu butuh presisi di bawah satu tick (jarang), pakai $realtime, yang mengembalikan real.
%t otomatis memformat waktu dengan lebar default yang dipilih simulator. %0t menghilangkan padding-nya.
Mengambil Sampel di Tepi Clock
Idiom yang rapi untuk memantau desain sekuensial: blok always @(posedge clk) terpisah yang mencetak sekali per siklus:
Pola sampling ini menjamin satu baris log per clock, sangat cocok untuk pengujian regresi yang mencocokkan pola di output.
Mencatat Log ke File
Buka file dengan $fopen, lalu catat dengan $fdisplay (yang bekerja seperti $display tapi menulis ke file handle):
integer fd;
initial begin
fd = $fopen("results.txt", "w");
$fdisplay(fd, "test=%s status=%s", test_name, status);
$fclose(fd);
end
$fopen mengembalikan handle 32-bit; berikan sebagai argumen pertama ke $fdisplay, $fwrite, $fstrobe, dan seterusnya. Selebihnya, fungsi-fungsi itu identik dengan saudaranya yang mencetak ke konsol.
Selanjutnya
$display dan kawan-kawannya memberimu log teks. Untuk debug visual, yaitu mengamati sinyal sebagai tegangan dari waktu ke waktu, kamu butuh waveform VCD. Dokumen berikutnya, Dumpfile dan VCD, membahas $dumpfile dan $dumpvars, dua panggilan yang mengubah simulasimu menjadi waveform grafis yang bisa kamu telusuri.
Pertanyaan yang sering diajukan
Apa perbedaan $display dan $monitor di Verilog?
$display mencetak sekali, langsung, saat dijalankan, seperti printf di C. $monitor mendaftarkan daftar pantauan; setiap kali ada sinyal di daftar itu yang berubah, pesan berformatnya otomatis dicetak. Hanya satu $monitor yang bisa aktif pada satu waktu; memanggilnya lagi akan mengganti daftar pantauan sebelumnya.
Format specifier apa saja yang didukung $display di Verilog?
Yang umum: %b (biner), %d (desimal), %h (hex), %o (oktal), %c (satu karakter dari byte terendah), %s (string), %t (waktu simulasi), %m (nama instance hierarkis). Pakai bentuk %0d untuk menghilangkan padding di depan: %d memberi padding sampai lebar default, %0d tanpa padding sama sekali.
Apa itu $write di Verilog?
$write mirip $display, tapi tidak menambahkan baris baru. Berguna saat kamu ingin membangun satu baris output dari beberapa panggilan. $display di akhir baris (tanpa argumen atau dengan baris baru di ujungnya) menutup baris itu.
Bagaimana cara mencetak waktu simulasi di Verilog?
Pakai $time (atau $realtime untuk resolusi di bawah satu tick) dengan format specifier %t: $display("at time %t: ...", $time);. Pakai %0t untuk menghilangkan padding default-nya. Untuk hitungan satuan waktu sebagai integer biasa, %0d dengan $time juga bisa: $display("t=%0d", $time);.