משפחת printf של Verilog
שלוש משימות מערכת מאפשרות להדפיס ל-stdout של הסימולטור:
$display: מדפיס פעם אחת ומוסיף ירידת שורה.$write: מדפיס פעם אחת, בלי ירידת שורה.$monitor: מדפיס אוטומטית בכל פעם שאות במעקב משתנה.
שלושתן מקבלות מחרוזת פורמט ורשימת ארגומנטים, בדיוק כמו printf. מצייני הפורמט דומים, אבל ייחודיים ל-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מרפד לרוחב ברירת מחדל לפי גודל האופרנד. ל-regשל 8 ביטים זה 3 תווים (מקום ל-255). הרווחים המובילים יכולים להיראות מכוערים בפלט טבלאי, אז השתמשו ב-%0dכדי לבטל אותם.- ל-
%h,%b,%oיש ריפוד דומה כברירת מחדל. רוב קוד ה-testbench משתמש בגרסאות%0כשהיישור לא מועיל. - ירידת השורה בסוף אוטומטית. אל תשימו
\nבסוף מחרוזת פורמט של$display, אחרת תקבלו שורה ריקה.
מצייני פורמט
הסט ש-Verilog תומכת בו:
| מציין | משמעות |
|---|---|
%b | בינארי |
%d | עשרוני (עם סימן אם האות מוצהר עם סימן) |
%h או %x | הקסדצימלי |
%o | אוקטלי |
%c | תו ASCII יחיד (8 הביטים התחתונים) |
%s | מחרוזת |
%t | זמן סימולציה |
%m | השם ההיררכי של התחום הנוכחי |
%% | % מילולי |
%0X | בלי ריפוד מוביל, לכל אחד מ-%b, %d וכו' |
%b, %d, %h, %o הם הארבעה שתשתמשו בהם ב-95% מהזמן. %t הוא הבא בתור: בכל פעם שרוצים שורת לוג עם חותמת זמן.
$write: בלי ירידת שורה
$write זהה ל-$display, רק שהוא לא מוסיף ירידת שורה:
פלט:
abc
done
שימושי לבניית שורה אחת מגוף של לולאה:
$write("[");
for (integer i = 0; i < 8; i = i + 1) $write("%h ", arr[i]);
$display("]");
$monitor: הדפסה אוטומטית בשינוי
$monitor רושם רשימת מעקב. הסימולטור מחשב מחדש ומדפיס בכל פעם ש_אות כלשהו_ שמוזכר במחרוזת הפורמט משתנה:
תראו שלוש שורות, אחת לכל שינוי בכניסות. אין צורך לקרוא ידנית ל-$display אחרי כל שינוי בגירוי: $monitor עושה את זה.
שתי מגבלות:
- רק
$monitorאחד יכול להיות פעיל. קריאה נוספת לו מחליפה את רשימת המעקב הקודמת. השתמשו ב-$monitoroffוב-$monitoronכדי להשתיק זמנית ולהפעיל מחדש. - שינויים באותו צעד זמן מתכווצים להדפסה אחת. אם
aו-bמשתנים שניהם בזמן 5, ה-monitor מופעל פעם אחת עם שני הערכים החדשים, לא פעמיים.
מתי להשתמש בכל אחד
$display: רוב הפלט של testbench. קראו לו במפורש אחרי גירוי, אחרי מעברי מצב חשובים, או בתוך בלוק דגימהalways @(posedge clk).$write: כשרוצים לבנות שורה אחת מלולאה או מכמה חלקים קטנים.$monitor: כשרוצים לעקוב ברציפות אחרי קבוצה קטנה של אותות ולראות פלט רק כשהם משתנים. שימושי לדיבוג ראשוני; קשה יותר לשימוש בסקריפטים של רגרסיה, כי הפלט לא דטרמיניסטי מבחינת מספר השורות הכולל.
ברוב תהליכי העבודה $display מכסה הכול. פנו ל-$monitor רק כשפלט רציף שמונע משינויים הוא באמת מה שאתם צריכים.
עבודה עם זמן
$time מחזיר את זמן הסימולציה הנוכחי כמספר שלם של 64 ביטים. שלבו אותו עם %0t:
$display("at %0t: signal flipped", $time);
הפלט נראה כמו at 25: signal flipped (היחידה תלויה ב-timescale שלכם).
אם צריך דיוק של פחות מ-tick (נדיר), השתמשו ב-$realtime במקום: הוא מחזיר real.
%t מעצב אוטומטית זמן עם רוחב ברירת מחדל שהסימולטור בוחר. %0t מסיר את הריפוד.
דגימה בקצה השעון
ניב נקי למעקב אחרי תכנונים סדרתיים: בלוק always @(posedge clk) נפרד שמדפיס פעם אחת בכל מחזור:
תבנית הדגימה הזו מבטיחה שורת לוג אחת לכל שעון, מושלם לבדיקות רגרסיה שמשוות תבניות בפלט.
כתיבת לוג לקובץ
פותחים קובץ עם $fopen, וכותבים לוג עם $fdisplay (שעובד כמו $display אבל כותב ל-handle של קובץ):
integer fd;
initial begin
fd = $fopen("results.txt", "w");
$fdisplay(fd, "test=%s status=%s", test_name, status);
$fclose(fd);
end
$fopen מחזיר handle של 32 ביטים; מעבירים אותו כארגומנט הראשון ל-$fdisplay, $fwrite, $fstrobe וכן הלאה. מעבר לזה, הפונקציות זהות לאחיות שלהן שמדפיסות לקונסולה.
מה הלאה
$display וחבריו נותנים לוגים טקסטואליים. לדיבוג ויזואלי, כלומר צפייה באותות כמתחים לאורך זמן, צריך waveform של VCD. המסמך הבא, Dumpfile ו-VCD, עוסק ב-$dumpfile וב-$dumpvars, שתי הקריאות שהופכות את הסימולציה ל-waveform גרפי שאפשר לגלול בו.
שאלות נפוצות
מה ההבדל בין $display ל-$monitor ב-Verilog?
$display מדפיס פעם אחת, מיד כשהוא מבוצע, כמו printf ב-C. $monitor רושם רשימת מעקב; בכל פעם שאות כלשהו ברשימה משתנה, ההודעה המעוצבת מודפסת אוטומטית. רק $monitor אחד יכול להיות פעיל בכל רגע; קריאה נוספת לו מחליפה את רשימת המעקב הקודמת.
באילו מצייני פורמט $display של Verilog תומך?
הנפוצים: %b (בינארי), %d (עשרוני), %h (הקסדצימלי), %o (אוקטלי), %c (תו יחיד מהבייט התחתון), %s (מחרוזת), %t (זמן סימולציה), %m (שם המופע ההיררכי). השתמשו בצורה %0d כדי לוותר על ריפוד באפסים מובילים: %d מרפד לרוחב ברירת מחדל, %0d לא מרפד בכלל.
מה זה $write ב-Verilog?
$write דומה ל-$display, אבל לא מוסיף ירידת שורה. שימושי כשרוצים לבנות שורת פלט מכמה קריאות. $display בסוף השורה (בלי ארגומנטים או עם ירידת שורה בסוף) סוגר את השורה.
איך מדפיסים את זמן הסימולציה ב-Verilog?
משתמשים ב-$time (או ב-$realtime לרזולוציה של פחות מ-tick) עם מציין הפורמט %t: $display("at time %t: ...", $time);. השתמשו ב-%0t כדי לבטל את ריפוד ברירת המחדל. לספירה פשוטה של יחידות זמן כמספר שלם, גם %0d עם $time עובד: $display("t=%0d", $time);.