ה-waveform שאתם באמת רוצים
$display מדפיס טקסט. זה בסדר לבדיקת שפיות מהירה, אבל ברגע שאתם מדבגים מונה עם בעיית תזמון או מכונת מצבים שנתקעה, אתם רוצים תמונה: אותות מצוירים כמתחים לאורך זמן, עם גלילה, זום וסמן שאפשר להניח על כל מעבר.
התמונה הזו היא קובץ VCD, ראשי תיבות של "value change dump": פורמט טקסט ש-IEEE תקננה במפרט המקורי של Verilog. כל סימולטור מודרני יכול לכתוב אותו, וכל מציג waveform מודרני יכול לקרוא אותו. המחיר של יצירתו הוא שתי שורות ב-testbench.
שתי השורות
בתוך בלוק initial, בדרך כלל אותו בלוק שמחזיק את הגירוי, מוסיפים:
$dumpfile("dump.vcd");
$dumpvars(0, test);
$dumpfileנותן שם לקובץ הפלט. אפשר להעביר כל נתיב; אם אין בו תיקייה, הקובץ נוצר בתיקיית העבודה של הסימולטור.$dumpvars(0, test)אומר "תעד כל אות בתחוםtestובכל תת תחום, באופן רקורסיבי, בלי הגבלת עומק".
זו כל ההגדרה. הריצו את הסימולציה ויהיה לכם dump.vcd שאפשר לפתוח ב-GTKWave או בלשונית Waveform של העורך בדפדפן.
דוגמה מלאה
הריצו את זה. לשונית ה-Waveform מציגה עכשיו שלושה אותות, clk, reset, count, מצוירים לאורך כל זמן הסימולציה. אפשר להניח סמן על כל נקודה ולקרוא את ערכי האותות באותו רגע, ואפשר לגרור כדי להגדיל ולבחון מחזור שעון בודד.
מה הארגומנט הראשון של $dumpvars עושה
$dumpvars(depth, scope) עובר על scope ועל כל תת מופע שהוא מכיל, ומתעד אותות עד depth רמות לעומק. ערכי העומק:
0: ללא הגבלה. כל אות ב-scopeובכל תת מודול מקונן מתועד.1: רק אותות שמוצהרים ישירות ב-scope. תת מודולים לא מתועדים.2:scopeועוד רמה אחת של תת מודולים.N:scopeועוד N-1 רמות של תת מודולים.
בפועל, $dumpvars(0, test) הוא מה שכמעט כל testbench משתמש בו. לתעד הכול זול (קובצי VCD שומרים רק מעברים, לא מצבים יציבים), ואתם לא רוצים לגלות באמצע דיבוג שהאות שאתם צריכים לא נשמר.
אם יש לכם תכנון גדול מאוד וה-VCD גדול מדי, אפשר לתעד באופן סלקטיבי:
$dumpvars(0, dut.inner_module); // just the interesting sub-module
$dumpvars(0, dut.regs); // just the register file
אפשר לקרוא ל-$dumpvars כמה פעמים כדי לצבור תחומים.
תיעוד אותות ספציפיים
$dumpvars יכול לקבל גם רשימה של אותות ספציפיים במקום תחום שלם:
$dumpvars(0, test.clk, test.reset, dut.count);
זה מתעד רק את שלושת האותות האלה. שימושי כשהתכנון עצום ואכפת לכם רק מקומץ אותות. בתכנונים קטנים פשוט יותר לתעד הכול.
שליטה בתיעוד באמצע הסימולציה
עוד שתי משימות הולכות יחד עם $dumpvars:
$dumpoff: משהה את התיעוד. שינויים נוספים לא נכנסים ל-VCD.$dumpon: ממשיך את התיעוד.
initial begin
$dumpfile("dump.vcd");
$dumpvars(0, test);
// ... interesting region ...
#1000 $dumpoff;
// ... long boring region we don't want in the VCD ...
#5000 $dumpon;
// ... another interesting region ...
end
כך מדלגים על החלק המשעמם של "ריצה של מיליון מחזורים" בבדיקה ארוכה, בלי לייצר קובץ VCD של 5GB.
צפייה בתוצאה
שתי דרכים עיקריות:
בעורך שבדפדפן
העורך בדף הזה מציג קובצי VCD ישירות. הריצו את הסימולציה ועברו ללשונית Waveform: האותות מופיעים עם ההיררכיה שלהם בחלונית אחת, וסמן נגרר באזור הגלים. לחצו בכל מקום על קו אות כדי להניח את הסמן; הוא מציג את ערכי האותות באותו רגע בתגיות קטנות ליד שם כל אות.
ב-GTKWave
אם הרצתם את הסימולציה מקומית (iverilog -o sim test.v ואז vvp sim), פתחו את קובץ ה-VCD שנוצר כך:
gtkwave dump.vcd
GTKWave טוען את הקובץ, מציג את עץ התחומים בחלונית משלו, ומחכה שתגררו אותות לאזור ה-waveform. לחיצה ימנית על אות של כמה ביטים מאפשרת לשנות את פורמט התצוגה (בינארי, הקסדצימלי, עשרוני, אנלוגי). השתמשו בתיבת החיפוש שבתחתית כדי לקפוץ לזמנים מסוימים או למעברים של אותות.
תבניות נפוצות
עוזר קטן ל-testbench
רוב קובצי ה-testbench מתחילים בדיוק בבלוק הזה. אפשר לשמור אותו קצר על ידי איחוד הכול ב-initial אחד:
initial begin
$dumpfile("dump.vcd");
$dumpvars(0, test);
// ... stimulus ...
$finish;
end
תיעוד מותנה
בסביבת בדיקות שבה רוצים פלט VCD רק לבדיקות שנכשלו:
initial begin
if (DUMP_VCD) begin
$dumpfile("dump.vcd");
$dumpvars(0, test);
end
// ... stimulus ...
end
DUMP_VCD יהיה parameter שמגדירים משורת הפקודה או לפי מצב הבדיקה. חוסך מקום בדיסק בחבילות רגרסיה.
תיעוד זיכרונות
זיכרונות (unpacked arrays) לא מתועדים על ידי $dumpvars כברירת מחדל, כי הם יכולים להיות עצומים. השתמשו במפורש ב-$dumpvars(0, dut.memory) אם אתם רוצים אותם, או ב-$dumpmem בחלק מהסימולטורים.
טעויות נפוצות
קובץ VCD ריק. שכחתם את $dumpfile או את $dumpvars, או שהסימולציה קראה ל-$finish לפני שאות כלשהו השתנה. הריצו לפחות כמה יחידות זמן אחרי ההגדרה.
אותות חסרים ב-waveform. התחום שהעברתם לא כלל אותם. $dumpvars(0, dut) מתעד רק את מה שבתוך dut; אם ה-testbench מזין אותות ברמת test, הם לא יופיעו. תמיד תעדו מתחום ה-testbench: $dumpvars(0, test).
קובץ ה-VCD ענק. סימולציה ארוכה עם אותות רחבים שמשתנים מהר מייצרת הרבה שורות VCD. שלושה פתרונות: לתעד תחום צר יותר, להשתמש ב-$dumpoff/$dumpon סביב החלקים המשעממים, או לעבור לפורמט קומפקטי יותר כמו FST (ש-iverilog ו-GTKWave תומכים בו עם הדגלים -fst).
מה הלאה
המסמך האחרון בפרק הזה, Timescale והשהיות, מסביר את ההנחיה \timescaleואיך#delay` ממופה בפועל לזמן אמיתי. אחרי זה תסיימו את המסמכים מקצה לקצה.
שאלות נפוצות
מה זה קובץ VCD ב-Verilog?
VCD הוא ראשי תיבות של Value Change Dump: פורמט טקסט לתיעוד כל מעבר של אות במהלך הסימולציה. הסימולטור כותב את הערך ההתחלתי של כל אות בזמן 0, ואז כל שינוי עם חותמת הזמן שלו. מציגי waveform כמו GTKWave קוראים את הקובץ ומציגים אותו כדיאגרמת תזמון גרפית שאפשר לגלול ולהגדיל.
איך יוצרים קובץ VCD ב-Verilog?
מוסיפים שתי משימות מערכת בתוך בלוק initial ב-testbench: $dumpfile("dump.vcd"); נותן שם לקובץ הפלט, ו-$dumpvars(0, top_module); מתעד כל אות ב-top_module ומתחתיו. כשהסימולציה מסתיימת, יהיה לכם קובץ dump.vcd שאפשר לפתוח בכל מציג waveform.
מה המשמעות של $dumpvars(0, ...) ב-Verilog?
$dumpvars(depth, instance) מתעד אותות החל מ-instance ויורד depth רמות לעומק. $dumpvars(0, test) פירושו 'כל האותות בתחום test ובכל תת תחום, באופן רקורסיבי': העומק 0 מיוחד ומשמעותו ללא הגבלה. $dumpvars(1, test) היה מתעד רק אותות שנמצאים ישירות ב-test, ולא באף תת מודול שנוצר בו מופע.
למה קובץ ה-VCD שלי ריק ב-Verilog?
שלוש סיבות סבירות: לא קראתם בכלל ל-$dumpfile/$dumpvars; הסימולציה הגיעה ל-$finish לפני שאותות כלשהם השתנו (הריצו לפחות כמה יחידות זמן אחרי הקריאה ל-dump); או שהתחום שהעברתם ל-$dumpvars לא תואם את ההיררכיה בפועל. רצף מינימלי שעובד הוא $dumpfile("dump.vcd"); $dumpvars(0, test); #10; $finish;.